/* * 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 "i18n.h" #include "bar.h" #include "engine.h" #include "defs.h" #include "dbg.h" #define BTN_MAX 2 #define KEY_LONG_DUR 1.0 #define BANNER_DUR 3.0 #define CTXPOPUP_BTN_WIDTH 254 #define UBAR_ITEM_PADDING_X 45 #define UBAR_POPUP_PADDING_X 30 #define BUF_MAX 128 #define TITLE_DELETE_POPUP "Delete User" #define MESSAGE_DELETE_POPUP "Are you sure you want to delete user?
(All histories will be deleted)" #define MESSAGE_DELETE_BANNER "is deleted" #define TITLE_EDIT_POPUP "Edit User" #define MESSAGE_EDIT_BANNER "Editing is completed" #define MESSAGE_KIDS "It is not available to use some content for over age 17~4, in Kids mode." #define ASSERT(exp) if (!(exp)) { _ERR(#exp); abort(); } enum _ubar_state { UBAR_STATE_HIDE, UBAR_STATE_USER, UBAR_STATE_ITEM, UBAR_STATE_USER_CTXPOPUP, UBAR_STATE_ITEM_CTXPOPUP, UBAR_STATE_USER_POPUP, UBAR_STATE_ITEM_POPUP }; struct _ubar_item; struct _ubar_data { struct _ubar_item *user; Evas_Object *ly; Evas_Object *scr; Evas_Object *bx; Eina_List *list; Evas_Object *base; Ecore_Timer *key_timer; struct engine *eng; struct _ubar_item *cur; struct bar_cb focus_cb; enum _ubar_state state; Eina_List *popup_list; Evas_Object *popup_scr; Evas_Object *popup_box; }; struct _ubar_item { Evas_Object *eo; Evas_Object *ic_bg; Evas_Object *ic; Evas_Object *ctxpopup; Evas_Object *btn[BTN_MAX]; Evas_Object *popup; struct engine_ubar_item *it; struct _ubar_data *bar; }; struct _btn_info { const char *part; const char *text; void (*click_cb)(void *, Evas *, Evas_Object *, void *); }; static void _focused(void *data, Evas_Object *obj, void *ei) { struct _ubar_data *bar; struct _ubar_item *foc; if (!data) { _ERR("Invalid argument"); return; } foc = data; bar = foc->bar; bar->focus_cb.func(bar->focus_cb.data, foc->eo); switch (bar->state) { case UBAR_STATE_HIDE: elm_object_signal_emit(bar->user->eo, SIG_FOCUS_FROM_DOWN, SRC_PROG); bar->state = UBAR_STATE_USER; break; case UBAR_STATE_USER: elm_object_signal_emit(bar->user->eo, SIG_HIGHLIGHT, SRC_PROG); bar->state = UBAR_STATE_ITEM; break; case UBAR_STATE_ITEM: if (foc == bar->user) { elm_object_signal_emit(bar->user->eo, SIG_FOCUS_FROM_RIGHT, SRC_PROG); bar->state = UBAR_STATE_USER; } break; default: break; } bar->cur = foc; } static void _mouse_over(void *data, Evas *e, Evas_Object *obj, void *ei) { if (!obj) { _ERR("Invalid argument"); return; } if (elm_object_focus_get(obj)) return; elm_object_focus_set(obj, EINA_TRUE); } static int _add_user(struct _ubar_data *bar, Evas_Object *base) { struct _ubar_item *item; Evas_Object *ly, *ic_bg, *ic; if (!bar || !base) { _ERR("Invalid argument"); return -1; } item = calloc(1, sizeof(*item)); if (!item) { _ERR("calloc failed"); return -1; } ly = elm_layout_add(base); if (!ly) { _ERR("layout add failed"); free(item); return -1; } elm_layout_file_set(ly, EDJEFILE, GRP_USER); ic_bg = elm_icon_add(ly); if (!ic_bg) { _ERR("image add failed"); evas_object_del(ly); free(item); return -1; } elm_object_part_content_set(ly, PART_USER_THUMB_BG, ic_bg); ic = elm_icon_add(ly); if (!ic) { _ERR("image add failed"); evas_object_del(ly); free(item); return -1; } elm_object_part_content_set(ly, PART_USER_THUMB, ic); elm_object_part_content_set(base, PART_USER, ly); elm_object_focus_allow_set(ly, EINA_TRUE); evas_object_event_callback_add(ly, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, NULL); evas_object_smart_callback_add(ly, "focused", _focused, item); item->eo = ly; item->ic_bg = ic_bg; item->ic = ic; item->bar = bar; bar->user = item; return 0; } static int _add_items(struct _ubar_data *bar, Evas_Object *base) { Evas_Object *ly, *scr, *bx; if (!bar || !base) { _ERR("Invalid argument"); return -1; } ly = elm_layout_add(base); if (!ly) { _ERR("layout add failed"); return -1; } elm_layout_file_set(ly, EDJEFILE, GRP_UBAR); 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; } evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_box_horizontal_set(bx, EINA_TRUE); elm_box_padding_set(bx, elm_config_scale_get() * UBAR_ITEM_PADDING_X, 0); elm_object_part_content_set(ly, PART_UBAR_CONTENT, scr); evas_object_show(bx); elm_object_content_set(scr, bx); elm_object_part_content_set(base, PART_UBAR, ly); bar->ly = ly; bar->scr = scr; bar->bx = bx; bar->base = base; return 0; } static int _add_bar(struct bar_info *info, Evas_Object *base) { struct _ubar_data *bar; int r; if (!info || !info->data || !base) { _ERR("Invalid argument"); return -1; } bar = info->data; r = _add_user(bar, base); if (r < 0) return -1; r = _add_items(bar, base); if (r < 0) return -1; return 0; } static int _update_user(struct _ubar_data *bar, struct engine_ubar_item *it) { struct _ubar_item *item; const char *thumb_bg; const char *thumb; const char *name; if (!bar || !it) { _ERR("Invalid argument"); return -1; } item = bar->user; name = NULL; thumb_bg = NULL; thumb = NULL; engine_ubar_item_get_info(it, &name, &thumb_bg, &thumb, NULL, NULL); elm_image_file_set(item->ic_bg, thumb_bg ? thumb_bg : DEF_USER_THUMB_BG, NULL); elm_image_file_set(item->ic, thumb ? thumb : DEF_USER_THUMB, NULL); elm_object_part_text_set(item->eo, PART_USER_NAME, name ? name : DEF_USER_NAME); engine_ubar_item_set_visible(it, true); return 0; } static struct _ubar_item *_pack_item(struct _ubar_data *bar, struct engine_ubar_item *it) { Evas_Object *ly, *ic_bg, *ic; struct _ubar_item *item; const char *name; const char *thumb_bg; const char *thumb; if (!bar || !it) return NULL; item = calloc(1, sizeof(*item)); if (!item) { _ERR("calloc failed"); return NULL; } ly = elm_layout_add(bar->bx); if (!ly) { _ERR("layout add failed"); free(item); return NULL; } elm_layout_file_set(ly, EDJEFILE, GRP_UBAR_ITEM); ic_bg = elm_icon_add(ly); if (!ic_bg) goto err; elm_object_part_content_set(ly, PART_USER_THUMB_BG, ic_bg); ic = elm_icon_add(ly); if (!ic) goto err; elm_object_part_content_set(ly, PART_USER_THUMB, ic); evas_object_show(ly); elm_object_focus_allow_set(ly, EINA_TRUE); item->eo = ly; item->ic_bg = ic_bg; item->ic = ic; item->bar = bar; item->it = it; name = NULL; thumb_bg = NULL; thumb = NULL; engine_ubar_item_get_info(item->it, &name, &thumb_bg, &thumb, NULL, NULL); elm_object_part_text_set(item->eo, PART_USER_NAME, name ? name : DEF_USER_NAME); elm_image_file_set(item->ic_bg, thumb_bg ? thumb_bg : DEF_UBAR_ITEM_THUMB_BG, NULL); elm_image_file_set(item->ic, thumb ? thumb : DEF_UBAR_ITEM_THUMB, NULL); evas_object_event_callback_add(ly, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, NULL); evas_object_smart_callback_add(ly, "focused", _focused, item); elm_box_pack_end(bar->bx, ly); engine_ubar_item_set_visible(item->it, true); return item; err: _ERR("image add failed"); evas_object_del(ly); free(item); return NULL; } static int _update_items(struct _ubar_data *bar, void *eng) { const Eina_List *list; Eina_List *l; struct engine_ubar_item *it; struct _ubar_item *item; int i; if (!bar || !eng) { _ERR("Invalid argument"); return -1; } EINA_LIST_FREE(bar->list, item) free(item); bar->cur = NULL; bar->list = NULL; list = engine_get_ubar_items(eng); if (!list) return -1; /* TODO: After deciding the muti-user rule, this part should be fixed */ i = 0; EINA_LIST_FOREACH((Eina_List *)list, l, it) { if (i > 3) break; if (i == 0) { _update_user(bar, it); i++; continue; } item = _pack_item(bar, it); if (!item) continue; bar->list = eina_list_append(bar->list, item); i++; } return 0; } static int _update(struct bar_info *info, void *eng, void *data) { struct _ubar_data *bar; int r; if (!info || !info->data || !eng) { _ERR("Invalid argument"); return -1; } bar = info->data; r = _update_items(bar, eng); if (r < 0) return -1; bar->eng = eng; return 0; } static Evas_Object *_get_item(struct bar_info *info) { struct _ubar_data *bar; if (!info || !info->data) { _ERR("Invalid argument"); return NULL; } bar = info->data; if (!bar->cur) bar->cur = bar->user; return bar->cur->eo; } static Eina_Bool _move_user(struct bar_info *info) { struct _ubar_data *bar; if (!info || !info->data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = info->data; elm_object_focus_set(bar->user->eo, EINA_TRUE); return EINA_TRUE; } static Eina_Bool _move_item(struct bar_info *info) { struct _ubar_data *bar; struct _ubar_item *item; if (!info || !info->data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = info->data; item = eina_list_data_get(bar->list); if (!item) return EINA_FALSE; elm_object_focus_set(item->eo, EINA_TRUE); return EINA_TRUE; } static Eina_Bool _is_move(struct bar_info *info, int dir) { struct _ubar_data *bar; if (!info || !info->data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = info->data; switch (dir) { case BAR_DIR_LEFT: case BAR_DIR_DOWN: if (bar->state != UBAR_STATE_USER) return EINA_FALSE; if (bar->cur == bar->user) return EINA_TRUE; break; default: return EINA_FALSE; } return EINA_FALSE; } static enum bar_event _move_right(struct bar_info *info) { struct _ubar_data *bar; Eina_Bool r; if (!info || !info->data) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; if (bar->state == UBAR_STATE_USER) r = _move_item(info); else r = EINA_FALSE; return r ? BAR_EVENT_DONE : BAR_EVENT_PASS; } static enum bar_event _move_left(struct bar_info *info) { struct _ubar_data *bar; Eina_Bool r; if (!info || !info->data) { _ERR("Invalid argumnet"); return BAR_EVENT_ERROR; } bar = info->data; if (bar->state != UBAR_STATE_USER && bar->state != UBAR_STATE_ITEM) return BAR_EVENT_ERROR; if (eina_list_data_get(bar->list) == bar->cur) r = _move_user(info); else r = EINA_FALSE; return r ? BAR_EVENT_DONE : BAR_EVENT_PASS; } static void _destroy_ctxpopup(struct _ubar_item *item) { int i; ASSERT(item); evas_object_del(item->ctxpopup); item->ctxpopup = NULL; for (i = 0; i < BTN_MAX; i++) { memset(item->btn, 0x00, sizeof(item->btn)); item->btn[i] = NULL; } } static void _destroy_popup(struct _ubar_item *item) { ASSERT(item); evas_object_del(item->popup); item->popup = NULL; switch (item->bar->state) { case UBAR_STATE_USER_POPUP: item->bar->state = UBAR_STATE_USER; break; case UBAR_STATE_ITEM_POPUP: item->bar->state = UBAR_STATE_ITEM; break; default: break; } } static enum bar_event _back(struct bar_info *info) { struct _ubar_data *bar; enum bar_event r; if (!info || !info->data) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; switch (bar->state) { case UBAR_STATE_USER: r = BAR_EVENT_MOVE; break; case UBAR_STATE_ITEM: r = _move_user(info) ? BAR_EVENT_DONE : BAR_EVENT_PASS; break; case UBAR_STATE_USER_CTXPOPUP: _destroy_ctxpopup(bar->user); bar->state = UBAR_STATE_USER; r = BAR_EVENT_DONE; break; case UBAR_STATE_ITEM_CTXPOPUP: _destroy_ctxpopup(bar->cur); bar->state = UBAR_STATE_ITEM; r = BAR_EVENT_DONE; break; case UBAR_STATE_USER_POPUP: _destroy_popup(bar->user); r = BAR_EVENT_DONE; break; case UBAR_STATE_ITEM_POPUP: _destroy_popup(bar->cur); r = BAR_EVENT_DONE; break; default: return BAR_EVENT_ERROR; } return r; } static Eina_Bool _add_btn(Evas_Object *p, struct _ubar_item *item, struct _btn_info *btn_info) { Evas_Object *btn, *firstbtn; int i; if (!p || !item) { _ERR("Invalid argument"); return EINA_FALSE; } firstbtn = NULL; for (i = 0; i < BTN_MAX; i++) { btn = elm_button_add(p); if (!btn) { _ERR("failed to create button"); memset(item->btn, 0x00, sizeof(item->btn)); return EINA_FALSE; } elm_object_part_content_set(p, btn_info[i].part, btn); elm_object_text_set(btn, btn_info[i].text); evas_object_show(btn); item->btn[i] = btn; evas_object_event_callback_add(btn, EVAS_CALLBACK_MOUSE_DOWN, btn_info[i].click_cb, item); evas_object_event_callback_add(btn, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, NULL); if (i == 0) firstbtn = btn; } if (firstbtn) elm_object_focus_set(firstbtn, EINA_TRUE); return EINA_TRUE; } static void _popup_cancel_clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { _destroy_popup(data); } static Evas_Object *_add_popup(Evas_Object *base, const char *title, const char *style) { Evas_Object *popup, *win; if (!base || !title) { _ERR("Invalid argument"); return NULL; } win = elm_object_parent_widget_get(base); if (!win) { _ERR("failed to get win eo"); return NULL; } popup = elm_popup_add(win); if (!popup) { _ERR("failed to create popup"); return NULL; } if (style) elm_object_style_set(popup, style); elm_object_part_text_set(popup, PART_POPUP_TEXT, title); elm_popup_orient_set(popup, ELM_POPUP_ORIENT_CENTER); elm_object_focus_allow_set(popup, EINA_FALSE); return popup; } static void _add_banner(struct _ubar_item *item) { Evas_Object *banner, *win; if (!item) { _ERR("Invalid argument"); return; } win = elm_object_parent_widget_get(item->bar->base); if (!win) { _ERR("failed to get win eo"); return; } banner = elm_popup_add(win); if (!banner) { _ERR("failed to create popup"); return; } elm_object_style_set(banner, STYLE_POPUP_BOTTOM_1LINE); elm_popup_orient_set(banner, ELM_POPUP_ORIENT_BOTTOM); elm_object_text_set(banner, MESSAGE_DELETE_BANNER); elm_popup_timeout_set(banner, BANNER_DUR); elm_object_focus_allow_set(banner, EINA_FALSE); evas_object_show(banner); } static void _popup_delete_clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { _destroy_popup(data); _add_banner(data); } static Eina_Bool _add_arrow(struct _ubar_item *item, Evas_Object *p, const char *group, const char *part) { Evas_Object *ly; if (!item || !p || !part || !group) { _ERR("Invalid argument"); return EINA_FALSE; } ly = elm_layout_add(p); if (!ly) { _ERR("failed to create icon"); evas_object_del(p); return EINA_FALSE; } elm_layout_file_set(ly, EDJEFILE, group); elm_object_part_content_set(p, part, ly); evas_object_show(ly); evas_object_event_callback_add(ly, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, item); return EINA_TRUE; } 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_label(Evas_Object *ly, const char *name) { Evas_Object *lbl; const char *s; if (!ly || !name) { _ERR("Invalid argument"); return NULL; } lbl = elm_label_add(ly); if (!lbl) { _ERR("failed to add label"); return NULL; } elm_object_style_set(lbl, STYLE_LABEL_SLIDE_CENTER_22); 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_object_text_set(lbl, name); 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 void _popup_user_unfocused(void *data, Evas_Object *obj, void *ei) { elm_object_signal_emit(obj, SIG_UNFOCUS, SRC_PROG); } static void _popup_user_focused(void *data, Evas_Object *obj, void *ei) { elm_object_signal_emit(obj, SIG_FOCUS, SRC_PROG); } static struct _ubar_item *_pack_users(struct _ubar_data *bar, struct engine_ubar_item *it, Evas_Object *p) { Evas_Object *ly, *ic, *ic_bg, *lbl; const char *name, *thumb_bg, *thumb; bool visible; int age; struct _ubar_item *item; char buf[BUF_MAX]; if (!it || !bar) { _ERR("Invalid argument"); return NULL; } engine_ubar_item_get_info(it, &name, &thumb_bg, &thumb, &age, &visible); if (visible) return NULL; item = calloc(1, sizeof(*item)); if (!item) { _ERR("calloc failed"); return NULL; } ly = elm_layout_add(p); if (!ly) { _ERR("failed to create layout"); evas_object_del(p); return NULL; } elm_layout_file_set(ly, EDJEFILE, GRP_UBAR_POPUP_ITEM); ic = elm_icon_add(ly); if (!ic) { _ERR("failed to create icon"); evas_object_del(p); return NULL; } elm_object_part_content_set(ly, PART_USER_THUMB, ic); ic_bg = elm_icon_add(ly); if (!ic_bg) { _ERR("failed to create icon"); evas_object_del(p); return NULL; } elm_object_focus_allow_set(ly, EINA_TRUE); elm_object_part_content_set(ly, PART_USER_THUMB_BG, ic_bg); evas_object_show(ly); if (age > 0) { snprintf(buf, sizeof(buf), "%d", age); elm_object_part_text_set(ly, PART_USER_AGE, buf); elm_object_signal_emit(ly, SIG_SHOW_AGE, SRC_PROG); } lbl = _add_label(ly, name); if (!lbl) { _ERR("failed to create name"); evas_object_del(p); return NULL; } elm_object_part_content_set(ly, PART_USER_NAME_POPUP, lbl); elm_image_file_set(ic_bg, thumb_bg ? thumb_bg : DEF_UBAR_ITEM_THUMB_BG, NULL); elm_image_file_set(ic, thumb ? thumb : DEF_UBAR_ITEM_THUMB_BG, NULL); elm_box_pack_end(p, ly); evas_object_smart_callback_add(ly, "focused", _popup_user_focused, bar); evas_object_smart_callback_add(ly, "unfocused", _popup_user_unfocused, NULL); item->eo = ly; item->it = it; item->bar = bar; return item; } static Eina_Bool _load_users(struct _ubar_data *bar, Evas_Object *p) { Evas_Object *scr, *box; const Eina_List *list; Eina_List *l; struct engine_ubar_item *it; struct _ubar_item *item; if (!bar || !p) { _ERR("Invalid argument"); return EINA_FALSE; } scr = elm_scroller_add(p); if (!scr) { _ERR("failed to create scroll"); evas_object_del(p); return EINA_FALSE; } elm_scroller_policy_set(scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); box = elm_box_add(scr); if (!box) { _ERR("failed to create box"); evas_object_del(p); return EINA_FALSE; } evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_box_horizontal_set(box, EINA_TRUE); elm_box_padding_set(box, elm_config_scale_get() * UBAR_POPUP_PADDING_X, 0); elm_object_part_content_set(p, PART_POPUP_USER, scr); evas_object_show(box); elm_object_content_set(scr, box); bar->popup_scr = scr; bar->popup_box = box; bar->popup_list = NULL; list = engine_get_ubar_items(bar->eng); if (!list) { _ERR("failed to get user list"); evas_object_del(p); return EINA_FALSE; } EINA_LIST_FOREACH((Eina_List *)list, l, it) { item = _pack_users(bar, it, box); if (!item) continue; bar->popup_list = eina_list_append(bar->popup_list, item); } return EINA_TRUE; } static Eina_Bool _add_popup_items(struct _ubar_item *item, Evas_Object *popup) { Evas_Object *ly, *entry; if (!item || !popup) { _ERR("Invalid argument"); return EINA_FALSE; } ly = elm_layout_add(popup); if (!ly) { _ERR("failed to create layout"); return EINA_FALSE; } elm_layout_file_set(ly, EDJEFILE, GRP_UBAR_POPUP); evas_object_show(ly); elm_object_content_set(popup, ly); if (!_add_arrow(item, ly, GRP_UBAR_LEFT_ARROW, PART_LEFT_ARROW)) { _ERR("failed to create left arrow"); evas_object_del(ly); return EINA_FALSE; } if (!_add_arrow(item, ly, GRP_UBAR_RIGHT_ARROW, PART_RIGHT_ARROW)) { _ERR("failed to create right arrow"); evas_object_del(ly); return EINA_FALSE; } if (!_load_users(item->bar, ly)) { _ERR("failed to create users"); evas_object_del(ly); return EINA_FALSE; } entry = elm_entry_add(ly); if (!entry) { _ERR("failed to create entry"); evas_object_del(ly); return EINA_FALSE; } elm_entry_single_line_set(entry, EINA_TRUE); elm_entry_input_panel_language_set(entry, ELM_INPUT_PANEL_LANG_ALPHABET); evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL); /* FIXME: After fixing about IME, focusing should be handled */ elm_object_focus_allow_set(entry, EINA_FALSE); elm_entry_cursor_end_set(entry); elm_object_part_content_set(ly, PART_POPUP_ENTRY, entry); evas_object_show(entry); elm_object_part_text_set(ly, PART_KIDS, MESSAGE_KIDS); return EINA_TRUE; } static void _popup_add_clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { struct _ubar_item *item; item = data; evas_object_del(item->popup); } static Eina_Bool _load_edit_popup(struct _ubar_item *item) { struct _ubar_data *bar; Evas_Object *popup; struct _ubar_item *cur; struct _btn_info btn_info[] = { { "button1", "Add", _popup_add_clicked }, { "button2", "Cancel", _popup_cancel_clicked } }; if (!item) { _ERR("Invalid argument"); return EINA_FALSE; } bar = item->bar; popup = _add_popup(bar->base, TITLE_EDIT_POPUP, STYLE_POPUP_USER); if (!popup) { _ERR("failed to create popup"); return EINA_FALSE; } if (!_add_btn(popup, item, btn_info)) { _ERR("failed to create popup button"); evas_object_del(popup); return EINA_FALSE; } if (!_add_popup_items(item, popup)) { _ERR("failed to create popup user"); evas_object_del(popup); return EINA_FALSE; } evas_object_show(popup); item->popup = popup; if (bar->popup_list) { cur = eina_list_data_get(bar->popup_list); if (cur) elm_object_focus_set(cur->eo, EINA_TRUE); } switch (bar->state) { case UBAR_STATE_USER_CTXPOPUP: _destroy_ctxpopup(bar->user); bar->state = UBAR_STATE_USER_POPUP; break; case UBAR_STATE_ITEM_CTXPOPUP: _destroy_ctxpopup(bar->cur); bar->state = UBAR_STATE_ITEM_POPUP; break; default: evas_object_del(popup); return EINA_FALSE; } return EINA_TRUE; } static Eina_Bool _load_delete_popup(struct _ubar_item *item) { struct _ubar_data *bar; Evas_Object *popup; struct _btn_info btn_info[] = { { "button1", "Delete", _popup_delete_clicked }, { "button2", "Cancel", _popup_cancel_clicked } }; if (!item) { _ERR("Invalid argument"); return EINA_FALSE; } bar = item->bar; popup = _add_popup(bar->base, TITLE_DELETE_POPUP, STYLE_POPUP_1LINE_2BUTTON); if (!popup) { _ERR("failed to create popup"); return EINA_FALSE; } elm_object_text_set(popup, MESSAGE_DELETE_POPUP); if (!_add_btn(popup, item, btn_info)) { _ERR("failed to create popup button"); evas_object_del(popup); return EINA_FALSE; } item->popup = popup; switch (bar->state) { case UBAR_STATE_USER_CTXPOPUP: _destroy_ctxpopup(bar->user); bar->state = UBAR_STATE_USER_POPUP; break; case UBAR_STATE_ITEM_CTXPOPUP: _destroy_ctxpopup(item->bar->cur); bar->state = UBAR_STATE_ITEM_POPUP; break; default: evas_object_del(popup); return EINA_FALSE; } return EINA_TRUE; } static void _ctxpopup_edit_clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { _load_edit_popup(data); } static void _ctxpopup_delete_clicked(void *data, Evas *e, Evas_Object *obj, void *ei) { _load_delete_popup(data); } static Eina_Bool _add_popup_btn(struct _ubar_item *item, Evas_Object *base) { Evas_Object *btn, *firstbtn; int i; struct _btn_info btn_info[] = { { NULL, "Edit", _ctxpopup_edit_clicked }, { NULL, "Delete", _ctxpopup_delete_clicked } }; if (!item || !base) { _ERR("Invalid argument"); return EINA_FALSE; } firstbtn = NULL; for (i = 0; i < sizeof(btn_info) / sizeof(*btn_info); i++) { btn = elm_button_add(base); if (!btn) { _ERR("failed to add button"); memset(item->btn, 0x00, sizeof(item->btn)); return EINA_FALSE; } elm_object_style_set(btn, STYLE_BTN_HOVERTEXT); elm_object_text_set(btn, btn_info[i].text); evas_object_show(btn); elm_box_pack_end(base, btn); item->btn[i] = btn; if (i == 0) firstbtn = btn; evas_object_event_callback_add(btn, EVAS_CALLBACK_MOUSE_DOWN, btn_info[i].click_cb, item); evas_object_event_callback_add(btn, EVAS_CALLBACK_MOUSE_MOVE, _mouse_over, NULL); } if (firstbtn) elm_object_focus_set(firstbtn, EINA_TRUE); return EINA_TRUE; } static Eina_Bool _create_popup(struct _ubar_item *item) { Evas_Object *ctxpopup, *box, *win; Evas_Coord x, w; if (!item) { _ERR("Invalid argument"); return EINA_FALSE; } win = elm_object_parent_widget_get(item->bar->base); if (!win) { _ERR("failed to get win"); return EINA_FALSE; } ctxpopup = elm_ctxpopup_add(win); if (!ctxpopup) { _ERR("failed to create ctxpopup"); return EINA_FALSE; } elm_object_style_set(ctxpopup, STYLE_CTXPOPUP_HOVER); elm_ctxpopup_direction_priority_set(ctxpopup, 0, 0, 0, 0); evas_object_geometry_get(item->ic, &x, NULL, &w, NULL); evas_object_move(ctxpopup, (x - CTXPOPUP_BTN_WIDTH / 2 + w / 2) * elm_config_scale_get(), POSITION_CTXPOPUP_Y * elm_config_scale_get()); box = elm_box_add(ctxpopup); if (!box) { _ERR("failed to create popup box"); evas_object_del(ctxpopup); return EINA_FALSE; } elm_object_content_set(ctxpopup, box); evas_object_show(box); evas_object_show(ctxpopup); if (!_add_popup_btn(item, box)) { _ERR("failed to create popup button"); evas_object_del(ctxpopup); return EINA_FALSE; } elm_object_signal_emit(item->eo, SIG_HLIGHT_FROM_POPOVER, SRC_PROG); item->ctxpopup = ctxpopup; return EINA_TRUE; } static Eina_Bool _long_key_cb(void *data) { struct _ubar_data *bar; if (!data) { _ERR("Invalid argument"); return EINA_FALSE; } bar = data; switch (bar->state) { case UBAR_STATE_USER: _create_popup(bar->user); bar->state = UBAR_STATE_USER_CTXPOPUP; break; case UBAR_STATE_ITEM: _create_popup(bar->cur); bar->state = UBAR_STATE_ITEM_CTXPOPUP; break; default: break; } return EINA_TRUE; } static enum bar_event _enter(struct bar_info *info) { struct _ubar_data *bar; Eina_Bool r; if (!info || !info->data) { _ERR("Invalid argument"); return BAR_EVENT_ERROR; } bar = info->data; r = EINA_FALSE; switch (bar->state) { case UBAR_STATE_USER: case UBAR_STATE_ITEM: if (!bar->key_timer) bar->key_timer = ecore_timer_add(KEY_LONG_DUR, _long_key_cb, bar); r = EINA_TRUE; break; case UBAR_STATE_USER_CTXPOPUP: if (!bar->user->ctxpopup) break; if (elm_object_focus_get(bar->user->btn[0])) r = _load_edit_popup(bar->user); else r = _load_delete_popup(bar->user); break; case UBAR_STATE_ITEM_CTXPOPUP: if (!bar->cur->ctxpopup) break; if (elm_object_focus_get(bar->cur->btn[0])) r = _load_edit_popup(bar->cur); else r = _load_delete_popup(bar->cur); break; case UBAR_STATE_USER_POPUP: if (!bar->user->popup) break; _destroy_popup(bar->user); r = EINA_TRUE; break; case UBAR_STATE_ITEM_POPUP: if (!bar->cur->popup) break; _destroy_popup(bar->cur); r = EINA_TRUE; break; default: return BAR_EVENT_ERROR; } return r ? BAR_EVENT_DONE : BAR_EVENT_PASS; } static enum bar_event _key_up(struct bar_info *info, void *ei) { struct _ubar_data *bar; Ecore_Event_Key *ev; if (!info || !ei) return BAR_EVENT_ERROR; ev = ei; bar = info->data; if (!strcmp(ev->keyname, KEY_ENTER)) { if (!bar->key_timer) return BAR_EVENT_DONE; ecore_timer_del(bar->key_timer); bar->key_timer = NULL; } return BAR_EVENT_DONE; } static enum bar_event _key_down(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_BACK)) r = _back(info); else if (!strcmp(ev->keyname, KEY_RIGHT)) r = _move_right(info); else if (!strcmp(ev->keyname, KEY_LEFT)) r = _move_left(info); else if (!strcmp(ev->keyname, KEY_ENTER)) r = _enter(info); else r = BAR_EVENT_PASS; return r; } static void _hide(struct bar_info *info) { struct _ubar_data *bar; if (!info || !info->data) { _ERR("Invalid argument"); return; } bar = info->data; elm_object_signal_emit(bar->user->eo, SIG_UNFOCUS_TO_DOWN, SRC_PROG); bar->state = UBAR_STATE_HIDE; } static void _hide_bar(struct _ubar_data *bar) { struct _ubar_item *item; Eina_List *l; if (!bar) { _ERR("Invalid argument"); return; } elm_object_signal_emit(bar->user->eo, SIG_HIDE, SRC_PROG); EINA_LIST_FOREACH(bar->list, l, item) elm_object_signal_emit(item->eo, SIG_HIDE, SRC_PROG); elm_object_signal_emit(bar->ly, SIG_HIDE, SRC_PROG); } static void _release(struct bar_info *info) { struct _ubar_data *bar; struct _ubar_item *item; if (!info || !info->data) { _ERR("Invalid argument"); return; } bar = info->data; _hide_bar(bar); if (bar) { EINA_LIST_FREE(bar->list, item) { evas_object_del(item->eo); free(item); } evas_object_del(bar->user->eo); free(bar->user); evas_object_del(bar->ly); free(bar); bar = NULL; } free(info); info = NULL; } static struct bar_ops ubar_ops = { .add_bar = _add_bar, .update = _update, .get_item = _get_item, .hide = _hide, .is_move = _is_move, .move = _move_user, .key_down = _key_down, .key_up = _key_up, .release = _release, }; int init_user_bar(struct bar_info *info) { struct _ubar_data *bar; if (!info) return -1; bar = calloc(1, sizeof(*bar)); if (!bar) { _ERR("calloc failed"); return -1; } info->data = bar; info->ops = &ubar_ops; if (!info->cb.func) { _ERR("invalid callback function"); free(bar); return -1; } bar->focus_cb = info->cb; return 0; }