From 434964e8ceb787d44fc369e1eecf90faaf0322c2 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Mon, 7 Sep 2015 20:15:56 +0900 Subject: [PATCH 01/16] add manifest file to avoid smack error Change-Id: I4f6f59163a05bc0c2a7acb915eab88d81d881bea Signed-off-by: Minkyu Kang --- packaging/org.tizen.live-tv.manifest | 5 +++++ packaging/org.tizen.live-tv.spec | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 packaging/org.tizen.live-tv.manifest diff --git a/packaging/org.tizen.live-tv.manifest b/packaging/org.tizen.live-tv.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/packaging/org.tizen.live-tv.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/org.tizen.live-tv.spec b/packaging/org.tizen.live-tv.spec index 67c2ce5..256fda5 100644 --- a/packaging/org.tizen.live-tv.spec +++ b/packaging/org.tizen.live-tv.spec @@ -7,6 +7,7 @@ License: Apache-2.0 Source0: %{name}-%{version}.tar.gz Source1: %{name}.service Source2: %{name}.path +Source3: %{name}.manifest BuildRequires: cmake BuildRequires: pkgconfig(capi-appfw-application) @@ -27,7 +28,6 @@ BuildRequires: edje-bin %define _pkgdir %{_prefix}/apps/%{name} %define _bindir %{_pkgdir}/bin %define _resdir %{_pkgdir}/res -%define _datadir %{_pkgdir}/data %define _edjedir %{_resdir}/edje %define _manifestdir %{_datarootdir}/packages %define _sysuserdir /systemd/user @@ -38,6 +38,7 @@ Live TV application for Tizen TV. %prep %setup -q +cp %{SOURCE3} . %build cmake \ @@ -52,7 +53,6 @@ make %{?jobs:-j%jobs} %install %make_install -install --directory %{buildroot}/%{_datadir} install --directory %{buildroot}%{_libdir}%{_servicedir} install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}%{_sysuserdir} install -m 0644 %{SOURCE2} %{buildroot}%{_libdir}%{_sysuserdir} @@ -62,10 +62,10 @@ ln -sf ../%{name}.path %{buildroot}%{_libdir}%{_servicedir} rm -rf %{buildroot} %files +%manifest %{name}.manifest %defattr(-,root,root,-) %{_bindir}/* %{_resdir}/* -%{_datadir} %{_manifestdir}/%{name}.xml %{_libdir}%{_sysuserdir}/%{name}.service %{_libdir}%{_sysuserdir}/%{name}.path -- 2.7.4 From 2b91dc0f82b09c863c3dc5996a6b6a2d9c1aead0 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Tue, 8 Sep 2015 14:36:23 +0900 Subject: [PATCH 02/16] Delays to call tune after tv service resume Change-Id: Id9c9c4c10f5955ff2d70c48eba804cc09c9dd3df Signed-off-by: jinwoo.shin --- src/main.c | 47 +++++++++++++++++++++++++---------------------- src/view_pin.c | 2 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/main.c b/src/main.c index b400730..324e5d3 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ struct _appdata { tzsh_h tzsh; tzsh_tvsrv_h ta; Ecore_Timer *pause_timer; + int service_id; int is_signal; int is_channel; @@ -273,14 +274,30 @@ static void _resume(void *data) r = tv_resume(); if (r < 0) { _ERR("Resume tv service failed"); + ui_app_exit(); + return; - } else if (r > 0) { - r = tv_channel_tune(); - if (r < 0) { - _ERR("Tune channel failed"); + } + + /* Try to tune with service id if supplied from app control */ + if (ad->service_id > 0) { + r = tv_channel_tune_with_service_id(ad->service_id); + ad->service_id = 0; + + if (!r) { + ad->is_channel = true; return; } } + + r = tv_channel_tune(); + if (r < 0) { + ad->is_channel = false; + viewmgr_show_view(VIEW_ERROR); + viewmgr_update_view(VIEW_ERROR, UPDATE_TYPE_NOCHANNEL, NULL); + } else { + ad->is_channel = true; + } } static bool _create(void *data) @@ -409,25 +426,11 @@ static void _control(app_control_h control, void *data) ad = data; r = app_control_get_extra_data(control, KEY_SVCID, &svcid); - if (r == SERVICE_ERROR_NONE) { - r = tv_channel_tune_with_service_id(atoll(svcid)); - free(svcid); - if (!r) { - ad->is_channel = true; - viewmgr_show_view(VIEW_CHANNELINFO); - return; - } - } - - r = tv_channel_tune(); + if (r != SERVICE_ERROR_NONE) + return; - if (r < 0) { - ad->is_channel = false; - viewmgr_show_view(VIEW_ERROR); - viewmgr_update_view(VIEW_ERROR, UPDATE_TYPE_NOCHANNEL, NULL); - } else { - ad->is_channel = true; - } + ad->service_id = atoll(svcid); + free(svcid); } int main(int argc, char *argv[]) diff --git a/src/view_pin.c b/src/view_pin.c index bab97bc..b91800e 100644 --- a/src/view_pin.c +++ b/src/view_pin.c @@ -53,7 +53,7 @@ static void _send_message(struct _priv *priv, const char *result) service_destroy(service); } -static void _check_pincode(struct _priv *priv, const char *pincode) +static void _check_pincode(struct _priv *priv, char *pincode) { const struct tv_channel_info *channel_info; int r; -- 2.7.4 From d0579bc65a13b832594675da02b78f2006504c6b Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Tue, 8 Sep 2015 16:56:14 +0900 Subject: [PATCH 03/16] Temporal patch to disable channel lock Change-Id: Icc6c3aa28d20527a313f83016a4141e334ee158a Signed-off-by: jinwoo.shin --- src/view_action_menu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/view_action_menu.c b/src/view_action_menu.c index a73131b..bee69a3 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -123,6 +123,11 @@ static void _lock_clicked(void) static int _lock_state(void) { + return STATE_DISABLED; + + /* + FIXME: Temporal fix until video mute is ready. + const struct tv_channel_info *channel_info; int r; @@ -137,6 +142,7 @@ static int _lock_state(void) tv_channel_del_info(channel_info); return r; + */ } static void _channel_clicked(void) -- 2.7.4 From b91df1bcae3e185b381283a04f02c8afa9170619 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Wed, 9 Sep 2015 21:23:45 +0900 Subject: [PATCH 04/16] Update key event handler - Replaces ecore event handler to elm event handler Change-Id: I3824e5e219006cf6713ef9526a56a1f312e7d08e Signed-off-by: jinwoo.shin --- src/layout_channelinfo_search.c | 1 - src/main.c | 88 +++++++++++------------------------------ src/view_action_menu.c | 4 ++ src/view_channelnumber.c | 8 ++-- 4 files changed, 33 insertions(+), 68 deletions(-) diff --git a/src/layout_channelinfo_search.c b/src/layout_channelinfo_search.c index 3849fdf..6aaa01e 100644 --- a/src/layout_channelinfo_search.c +++ b/src/layout_channelinfo_search.c @@ -61,7 +61,6 @@ static void _tune_channel(void *data) _ERR("failed to tune with service id"); viewmgr_hide_view(VIEW_CHANNELINFO); - viewmgr_show_view(VIEW_CHANNELINFO); } static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, diff --git a/src/main.c b/src/main.c index 324e5d3..4c74363 100644 --- a/src/main.c +++ b/src/main.c @@ -77,84 +77,50 @@ static struct key_map g_kmap[] = { }, }; -static Eina_Bool _key_down_cb(void *data, int type, void *ei) +static Eina_Bool _event(void *data, Evas_Object *obj, Evas_Object *src, + Evas_Callback_Type type, void *ei) { struct _appdata *ad; - Evas_Event_Key_Down *ev = ei; size_t i, j; + char *keyname; + int update_type; if (!data) { _ERR("failed to get data"); - return false; + return EINA_FALSE; } ad = data; - if (!ad->is_channel) - return ECORE_CALLBACK_DONE; - - if (viewmgr_get_view_state(VIEW_PIN) == - VIEW_STATE_VISIBLE) - return ECORE_CALLBACK_PASS_ON; - - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { - if (viewmgr_active_view_count() > 0) - return ECORE_CALLBACK_PASS_ON; - } - - for (i = 0; i < sizeof(g_kmap) / sizeof(*g_kmap); i++) { - j = 0; - while (g_kmap[i].key[j]) { - if (!strcmp(ev->keyname, g_kmap[i].key[j])) { - viewmgr_update_view(g_kmap[i].view, - UPDATE_TYPE_INPUT_KEY_DOWN, ev); - return ECORE_CALLBACK_DONE; - } - j++; - } - } - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool _key_up_cb(void *data, int type, void *ei) -{ - struct _appdata *ad; - Evas_Event_Key_Up *ev = ei; - size_t i, j; - - if (!data) { - _ERR("failed to get data"); - return false; - } - - ad = data; if (!ad->is_channel) - return ECORE_CALLBACK_DONE; - - if (viewmgr_get_view_state(VIEW_PIN) == - VIEW_STATE_VISIBLE) - return ECORE_CALLBACK_PASS_ON; - - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { - if (viewmgr_active_view_count() > 0) - return ECORE_CALLBACK_PASS_ON; + return EINA_TRUE; + + switch (type) { + case EVAS_CALLBACK_KEY_DOWN: + keyname = ((Evas_Event_Key_Down *)ei)->keyname; + update_type = UPDATE_TYPE_INPUT_KEY_DOWN; + break; + case EVAS_CALLBACK_KEY_UP: + keyname = ((Evas_Event_Key_Up *)ei)->keyname; + update_type = UPDATE_TYPE_INPUT_KEY_UP; + break; + default: + return EINA_FALSE; } for (i = 0; i < sizeof(g_kmap) / sizeof(*g_kmap); i++) { j = 0; while (g_kmap[i].key[j]) { - if (!strcmp(ev->keyname, g_kmap[i].key[j])) { + if (!strcmp(keyname, g_kmap[i].key[j])) { viewmgr_update_view(g_kmap[i].view, - UPDATE_TYPE_INPUT_KEY_UP, ev); - return ECORE_CALLBACK_DONE; + update_type, ei); + return EINA_TRUE; } j++; } } - return ECORE_CALLBACK_PASS_ON; + return EINA_FALSE; } static Evas_Object *_add_win(const char *name) @@ -360,10 +326,7 @@ static bool _create(void *data) ad->win = win; tv_signal_cb_set(_tv_signal_cb, ad); - ad->key_down = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, - _key_down_cb, ad); - ad->key_up = ecore_event_handler_add(ECORE_EVENT_KEY_UP, - _key_up_cb, ad); + elm_object_event_callback_add(win, _event, ad); elm_config_focus_move_policy_set(ELM_FOCUS_MOVE_POLICY_IN); @@ -389,10 +352,7 @@ static void _terminate(void *data) if (ad->win) { tv_destroy(); - if (ad->key_down) - ecore_event_handler_del(ad->key_down); - if (ad->key_up) - ecore_event_handler_del(ad->key_up); + elm_object_event_callback_del(ad->win, _event, ad); viewmgr_remove_view(VIEW_CHANNELINFO); viewmgr_remove_view(VIEW_CHANNELNUMBER); diff --git a/src/view_action_menu.c b/src/view_action_menu.c index bee69a3..6c21921 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -278,6 +278,8 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, if (!strcmp(ev->keyname, KEY_BACK) || !strcmp(ev->keyname, KEY_BACK_REMOTE)) viewmgr_hide_view(VIEW_ACTION_MENU); + + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; } static input_handler key_handler = { @@ -363,6 +365,8 @@ static void _favorite_clicked_cb(int id, void *data, Evas_Object *obj) { if (id > 0) tv_channel_tune_with_service_id(id); + + viewmgr_hide_view(VIEW_ACTION_MENU); } static input_handler favorite_handler = { diff --git a/src/view_channelnumber.c b/src/view_channelnumber.c index 6a63655..bf1ce0c 100644 --- a/src/view_channelnumber.c +++ b/src/view_channelnumber.c @@ -75,7 +75,6 @@ static Eina_Bool _done_input(void *data) _ERR("invalid channel"); viewmgr_hide_view(VIEW_CHANNELNUMBER); - viewmgr_show_view(VIEW_CHANNELINFO); return ECORE_CALLBACK_CANCEL; } @@ -115,8 +114,11 @@ static void _channel_key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) + !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + _tune_channel(data); + } } static void _channel_mouse_down_cb(int id, void *data, Evas *e, @@ -245,7 +247,7 @@ static void _update_number_info(struct _priv *priv) static int _get_number(const char *keyname) { - static const char const *keys[] = { + static const char * const keys[] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 }; -- 2.7.4 From fbfc2393cf390509957d19b78c9c8d19bff09f56 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Tue, 15 Sep 2015 19:41:26 +0900 Subject: [PATCH 05/16] Restructuring channelinfo view and added animations - Each layout creates its own base layout to show animation effect - Added show/hide effect on each layout except search layout Change-Id: Ibf11a7e21cc6f43754886533b7207602b638fc5b Signed-off-by: jinwoo.shin --- data/view/channelinfo.edc | 282 +++++++++++++++++++++++++++++++++------- include/define.h | 8 +- include/view.h | 2 - src/layout_channelinfo.c | 100 ++++++++++---- src/layout_channelinfo_list.c | 137 ++++++++++++------- src/layout_channelinfo_search.c | 104 ++++++++++----- src/util.c | 3 +- src/view_channelinfo.c | 70 +--------- 8 files changed, 490 insertions(+), 216 deletions(-) diff --git a/data/view/channelinfo.edc b/data/view/channelinfo.edc index 0ebf575..8b7ece3 100644 --- a/data/view/channelinfo.edc +++ b/data/view/channelinfo.edc @@ -36,7 +36,53 @@ group { } group { - name, GRP_CHANNELINFO_LIST; + name, GRP_LAYOUT_CHANNELINFO; + parts { + part { + name, PART_CONTENT; + type, SWALLOW; + scale, 1; + description { + state, "default" 0.0; + rel1.relative, 1.0 0.5; + rel2.relative, 1.0 0.5; + min, 536 486; + align, 0.0 0.5; + fixed, 1 1; + visible, 0; + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + align, 1.0 0.5; + visible, 1; + } + } + } + programs { + program { + signal, SIGNAL_SHOW; + action, STATE_SET "show" 0.0; + target, PART_CONTENT; + transition, CUBIC_BEZIER 0.5 0.45 0.03 0.41 1.0; + } + program { + signal, SIGNAL_HIDE; + source, SOURCE_ELM; + action, STATE_SET "default" 0.0; + target, PART_CONTENT; + transition, CUBIC_BEZIER 0.167 0.25 0.46 0.45 1.0; + after, "hide_finished"; + } + program { + name, "hide_finished"; + action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; + } + } +} + +group { + name, GRP_LAYOUT_CHANNELINFO_LIST; images { image, "btn_navigation_up.png" COMP; image, "btn_navigation_down.png" COMP; @@ -48,18 +94,24 @@ group { scale, 1; description { state, "default" 0.0; - rel1.relative, 0.0 0.5; - rel2.relative, 0.0 0.5; + rel1.relative, 1.0 0.5; + rel2.relative, 1.0 0.5; min, 536 486; align, 0.0 0.5; fixed, 1 1; } + description { + state, "show" 0.0; + inherit, "default" 0.0; + align, 1.0 0.5; + } } part { name, "part.navigation_up"; type, IMAGE; scale, 1; description { + state, "default" 0.0; image.normal, "btn_navigation_up.png"; rel1 { to, "bg"; @@ -79,115 +131,194 @@ group { name, "padding.next_channel"; type, SPACER; description { + state, "default" 0.0; rel1 { - to_y, "part.navigation_up"; - relative, 0.0 1.0; + to, "part.navigation_up"; + relative, 0.5 1.0; } rel2 { - to_y, "part.navigation_up"; - relative, 1.0 1.0; + to, "part.navigation_up"; + relative, 0.5 1.0; } min, 0 20; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; } } part { - name, PART_CHANNELINFO_LIST_NEXT; - type, SWALLOW; + name, "clip_next"; + type, RECT; description { + state, "default" 0.0; rel1 { - to_y, "padding.next_channel"; - relative, 0.0 1.0; + to, "padding.next_channel"; + relative, 0.5 1.0; } rel2 { - to_y, "padding.next_channel"; - relative, 1.0 1.0; + to, "padding.next_channel"; + relative, 0.5 1.0; } min, 536 70; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; + color, 255 255 255 0; + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + color, 255 255 255 255; + } + } + part { + name, PART_CHANNELINFO_LIST_NEXT; + type, SWALLOW; + clip_to, "clip_next"; + description { + state, "default" 0.0; + rel1 { + to, "clip_next"; + offset, 0 20; + } + rel2 { + to, "clip_next"; + offset, 0 20; + } + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + rel1.offset, 0 0; + rel2.offset, 0 0; } } part { name, "padding.current_channel"; type, SPACER; description { + state, "default" 0.0; rel1 { - to_y, PART_CHANNELINFO_LIST_NEXT; - relative, 0.0 1.0; + to, "clip_next"; + relative, 0.5 1.0; } rel2 { - to_y, PART_CHANNELINFO_LIST_NEXT; - relative, 1.0 1.0; + to, "clip_next"; + relative, 0.5 1.0; } min, 0 32; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; } } part { - name, PART_CHANNELINFO_LIST_CURRENT; - type, SWALLOW; + name, "clip_current"; + type, RECT; description { + state, "default" 0.0; rel1 { - to_y, "padding.current_channel"; - relative, 0.0 1.0; + to, "padding.current_channel"; + relative, 0.5 1.0; } rel2 { - to_y, "padding.current_channel"; - relative, 1.0 1.0; + to, "padding.current_channel"; + relative, 0.5 1.0; } min, 536 174; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; + color, 255 255 255 0; + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + color, 255 255 255 255; + } + } + part { + name, PART_CHANNELINFO_LIST_CURRENT; + type, SWALLOW; + clip_to, "clip_current"; + description { + state, "default" 0.0; + rel1.to, "clip_current"; + rel2.to, "clip_current"; } } part { name, "padding.prev_channel"; type, SPACER; description { + state, "default" 0.0; rel1 { - to_y, PART_CHANNELINFO_LIST_CURRENT; - relative, 0.0 1.0; + to, PART_CHANNELINFO_LIST_CURRENT; + relative, 0.5 1.0; } rel2 { - to_y, PART_CHANNELINFO_LIST_CURRENT; - relative, 1.0 1.0; + to, PART_CHANNELINFO_LIST_CURRENT; + relative, 0.5 1.0; } min, 0 32; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; } } part { - name, PART_CHANNELINFO_LIST_PREV; - type, SWALLOW; + name, "clip_prev"; + type, RECT; description { + state, "default" 0.0; rel1 { - to_y, "padding.prev_channel"; - relative, 0.0 1.0; + to, "padding.prev_channel"; + relative, 0.5 1.0; } rel2 { - to_y, "padding.prev_channel"; - relative, 1.0 1.0; + to, "padding.prev_channel"; + relative, 0.5 1.0; } min, 536 70; - align, 0.0 0.0; + align, 0.5 0.0; fixed, 1 1; + color, 255 255 255 0; + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + color, 255 255 255 255; + } + } + part { + name, PART_CHANNELINFO_LIST_PREV; + type, SWALLOW; + clip_to, "clip_prev"; + description { + state, "default" 0.0; + rel1 { + to, "clip_prev"; + offset, 0 -20; + } + rel2 { + to, "clip_prev"; + offset, 0 -20; + } + } + description { + state, "show" 0.0; + inherit, "default" 0.0; + rel1.offset, 0 0; + rel2.offset, 0 0; } } part { name, "padding.navigation_down"; type, SPACER; description { + state, "default" 0.0; rel1 { - to_y, PART_CHANNELINFO_LIST_PREV; - relative, 0.0 1.0; + to, "clip_prev"; + relative, 0.5 1.0; } rel2 { - to_y, PART_CHANNELINFO_LIST_PREV; - relative, 1.0 1.0; + to, "clip_prev"; + relative, 0.5 1.0; } min, 0 20; align, 0.0 0.0; @@ -199,13 +330,14 @@ group { type, IMAGE; scale, 1; description { + state, "default" 0.0; image.normal, "btn_navigation_down.png"; rel1 { - to_y, "padding.navigation_down"; + to, "padding.navigation_down"; relative, 0.5 1.0; } rel2 { - to_y, "padding.navigation_down"; + to, "padding.navigation_down"; relative, 0.5 1.0; } min, 98 34; @@ -215,6 +347,66 @@ group { } } } + programs { + program { + signal, SIGNAL_SHOW; + action, STATE_SET "show" 0.0; + target, "bg"; + after, "show_current"; + after, "show_other"; + } + program { + name, "show_current"; + action, STATE_SET "show" 0.0; + target, "clip_current"; + transition, CUBIC_BEZIER 0.334 0.45 0.03 0.41 1.0; + } + program { + name, "show_other"; + action, STATE_SET "show" 0.0; + target, "clip_next"; + target, PART_CHANNELINFO_LIST_NEXT; + target, "clip_prev"; + target, PART_CHANNELINFO_LIST_PREV; + transition, CUBIC_BEZIER 0.401 0.45 0.03 0.41 1.0; + } + program { + signal, SIGNAL_HIDE; + source, SOURCE_ELM; + action, STATE_SET "default" 0.0; + target, "bg"; + transition, CUBIC_BEZIER 0.167 0.25 0.46 0.45 1.0; + sequence { + action, STATE_SET "default" 0.0; + target, "clip_next"; + target, PART_CHANNELINFO_LIST_NEXT; + target, "clip_prev"; + target, PART_CHANNELINFO_LIST_PREV; + target, "clip_current"; + + action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; + } + } + } +} + +group { + name, GRP_LAYOUT_CHANNELINFO_SEARCH; + parts { + part { + name, PART_CONTENT; + type, SWALLOW; + scale, 1; + description { + state, "default" 0.0; + rel1.relative, 1.0 0.0; + rel2.relative, 1.0 1.0; + min, 536 0; + align, 1.0 0.0; + fixed, 1 0; + } + } + } } group { diff --git a/include/define.h b/include/define.h index 4ff5bfd..ac98f3d 100644 --- a/include/define.h +++ b/include/define.h @@ -46,6 +46,9 @@ #define SIGNAL_NO_FAVORITE "elm,state,no_favorite" #define SIGNAL_TOGGLE "elm,state,toggle" #define SIGNAL_UNTOGGLE "elm,state,untoggle" +#define SIGNAL_SHOW "show" +#define SIGNAL_HIDE "hide" +#define SIGNAL_HIDE_FINISHED "elm,action,hide,finished" #define SIGNAL_TIMEOUT "timeout" #define FONT_REGULAR "TizenSans" @@ -95,11 +98,12 @@ #define LAYOUT_CHANNELINFO_SEARCH "LAYOUT_CHANNELINFO_SEARCH" #define GRP_VIEW_CHANNELINFO "grp.view.channelinfo" - -#define GRP_CHANNELINFO_LIST "grp.channelinfo.list" +#define GRP_LAYOUT_CHANNELINFO "grp.lavout.channelinfo.list" +#define GRP_LAYOUT_CHANNELINFO_LIST "grp.layout.channelinfo.list" #define PART_CHANNELINFO_LIST_NEXT "part.channelinfo.list.next" #define PART_CHANNELINFO_LIST_CURRENT "part.channelinfo.list.current" #define PART_CHANNELINFO_LIST_PREV "part.channelinfo.list.prev" +#define GRP_LAYOUT_CHANNELINFO_SEARCH "grp.layout.channelinfo.search" #define GRP_CHANNELINFO "grp.channelinfo" #define GRP_CHANNELINFO_SIMPLE "grp.channelinfo.simple" diff --git a/include/view.h b/include/view.h index 34abc88..db1a783 100644 --- a/include/view.h +++ b/include/view.h @@ -33,8 +33,6 @@ enum _update_op { STOP_HIDE_TIMER }; -void draw_channel_info(Evas_Object *obj, const struct tv_channel_info *channel_info); - view_class *view_channelnumber_get_vclass(void); view_class *view_channelinfo_get_vclass(void); view_class *view_error_get_vclass(void); diff --git a/src/layout_channelinfo.c b/src/layout_channelinfo.c index 3d9dec9..6226ae0 100644 --- a/src/layout_channelinfo.c +++ b/src/layout_channelinfo.c @@ -25,14 +25,22 @@ #include "view.h" #include "util.h" +static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, + Evas_Event_Key_Down *ev); + struct _priv { Evas_Object *base; Evas_Object *layout; + Evas_Object *channel; layoutmgr *lmgr; const struct tv_channel_info *channel_info; }; +static input_handler key_handler = { + .key_down = _key_down_cb, +}; + static void _update_channel_info(struct _priv *priv) { if (priv->channel_info) { @@ -47,13 +55,50 @@ static void _update_channel_info(struct _priv *priv) return; } - util_draw_channel_info(priv->layout, priv->channel_info); + util_draw_channel_info(priv->channel, priv->channel_info); +} + +static bool _draw_channel_layout(struct _priv *priv) +{ + priv->channel = elm_layout_add(priv->base); + if (!priv->channel) { + _ERR("failed to create channel layout"); + return false; + } + + elm_layout_file_set(priv->channel, EDJEFILE, GRP_CHANNELINFO); + elm_object_content_set(priv->base, priv->channel); + + return true; +} + +static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, + Evas_Event_Key_Down *ev) +{ + if (!strcmp(ev->keyname, KEY_BACK) || + !strcmp(ev->keyname, KEY_BACK_REMOTE) || + !strcmp(ev->keyname, KEY_EXIT)) { + viewmgr_hide_view(VIEW_CHANNELINFO); + } +} + +static void _hide_finished_cb(void *data, Evas_Object *obj, + const char *emission, const char *source) +{ + struct _priv *priv; + + if (!data) + return; + + priv = data; + + evas_object_hide(priv->base); } static bool _create(layoutmgr *lmgr, void *data) { struct _priv *priv; - Evas_Object *base, *layout; + Evas_Object *win; priv = calloc(1, sizeof(*priv)); if (!priv) { @@ -61,32 +106,39 @@ static bool _create(layoutmgr *lmgr, void *data) return false; } - base = layoutmgr_get_base(lmgr); + win = layoutmgr_get_base(lmgr); - layout = elm_layout_add(base); - if (!layout) { + priv->base = elm_layout_add(win); + if (!priv->base) { _ERR("failed to create layout"); free(priv); return false; } - if (!elm_layout_file_set(layout, EDJEFILE, GRP_CHANNELINFO)) - goto error; - priv->base = base; - priv->layout = layout; - priv->lmgr = lmgr; + elm_layout_file_set(priv->base, EDJEFILE, GRP_LAYOUT_CHANNELINFO); + evas_object_size_hint_weight_set(priv->base, + EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, priv->base); + elm_object_focus_allow_set(priv->base, EINA_TRUE); - layoutmgr_set_layout_data(lmgr, LAYOUT_CHANNELINFO, priv); + if (!_draw_channel_layout(priv)) { + _ERR("failed to create channel layout"); - return true; + evas_object_del(priv->base); + free(priv); -error: - _ERR("failed to create layout"); - evas_object_del(layout); - free(priv); + return false; + } - return false; + inputmgr_add_callback(priv->base, 0, &key_handler, priv); + elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, + SOURCE_ELM, _hide_finished_cb, priv); + layoutmgr_set_layout_data(lmgr, LAYOUT_CHANNELINFO, priv); + + priv->lmgr = lmgr; + + return true; } static void _destroy(void *layout_data) @@ -103,7 +155,11 @@ static void _destroy(void *layout_data) priv->channel_info = NULL; } - evas_object_del(priv->layout); + inputmgr_remove_callback(priv->base, &key_handler); + elm_layout_signal_callback_del(priv->base, SIGNAL_HIDE_FINISHED, + SOURCE_ELM, _hide_finished_cb); + + evas_object_del(priv->base); free(priv); } @@ -118,8 +174,9 @@ static void _show(void *layout_data) _update_channel_info(priv); - elm_object_content_set(priv->base, priv->layout); - evas_object_show(priv->layout); + evas_object_show(priv->base); + + elm_object_focus_set(priv->base, EINA_TRUE); } static void _hide(void *layout_data) @@ -131,8 +188,7 @@ static void _hide(void *layout_data) priv = layout_data; - evas_object_hide(priv->layout); - elm_object_content_unset(priv->base); + elm_layout_signal_emit(priv->base, SIGNAL_HIDE, SOURCE_ELM); } static void _update(void *layout_data, int update_type, void *data) diff --git a/src/layout_channelinfo_list.c b/src/layout_channelinfo_list.c index 6cb64de..760d565 100644 --- a/src/layout_channelinfo_list.c +++ b/src/layout_channelinfo_list.c @@ -25,6 +25,9 @@ #include "tv.h" #include "view.h" +static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, + Evas_Event_Key_Down *ev); + enum _order { CHANNEL_NEXT, CHANNEL_PREV @@ -32,7 +35,6 @@ enum _order { struct _priv { Evas_Object *base; - Evas_Object *layout; Evas_Object *prev_channel; Evas_Object *current_channel; Evas_Object *next_channel; @@ -41,6 +43,10 @@ struct _priv { layoutmgr *lmgr; }; +static input_handler key_handler = { + .key_down = _key_down_cb, +}; + static int _set_next_channel(struct _priv *priv, int order) { const struct tv_channel_info *next, *current, *channel; @@ -140,9 +146,61 @@ static void _update_channel_info(struct _priv *priv) tv_channel_del_list(channel_list); } +static bool _draw_channel_layout(struct _priv *priv) +{ + priv->next_channel = util_add_layout(priv->base, + GRP_CHANNELINFO_SIMPLE); + if (!priv->next_channel) + return false; + + elm_object_part_content_set(priv->base, + PART_CHANNELINFO_LIST_NEXT, priv->next_channel); + + priv->current_channel = util_add_layout(priv->base, GRP_CHANNELINFO); + if (!priv->current_channel) + return false; + + elm_object_part_content_set(priv->base, + PART_CHANNELINFO_LIST_CURRENT, priv->current_channel); + + priv->prev_channel = util_add_layout(priv->base, + GRP_CHANNELINFO_SIMPLE); + if (!priv->prev_channel) + return false; + + elm_object_part_content_set(priv->base, + PART_CHANNELINFO_LIST_PREV, priv->prev_channel); + + return true; +} + +static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, + Evas_Event_Key_Down *ev) +{ + if (!strcmp(ev->keyname, KEY_BACK) || + !strcmp(ev->keyname, KEY_BACK_REMOTE) || + !strcmp(ev->keyname, KEY_EXIT)) { + viewmgr_hide_view(VIEW_CHANNELINFO); + } +} + +static void _hide_finished_cb(void *data, Evas_Object *obj, + const char *emission, const char *source) +{ + struct _priv *priv; + + if (!data) + return; + + priv = data; + + evas_object_hide(priv->base); +} + static bool _create(layoutmgr *lmgr, void *data) { struct _priv *priv; + Evas_Object *win; priv = calloc(1, sizeof(*priv)); if (!priv) { @@ -150,57 +208,40 @@ static bool _create(layoutmgr *lmgr, void *data) return false; } - priv->base = layoutmgr_get_base(lmgr); + win = layoutmgr_get_base(lmgr); + + priv->base = elm_layout_add(win); + if (!priv->base) { + _ERR("failed to create base layout"); + free(priv); - priv->layout = elm_layout_add(priv->base); - if (!priv->layout) { - _ERR("failed to create layout"); return false; } - if (!elm_layout_file_set(priv->layout, EDJEFILE, GRP_CHANNELINFO_LIST)) - goto error; - priv->next_channel = util_add_layout(priv->layout, - GRP_CHANNELINFO_SIMPLE); - if (!priv->next_channel) - goto error; - elm_object_part_content_set(priv->layout, - PART_CHANNELINFO_LIST_NEXT, priv->next_channel); + elm_layout_file_set(priv->base, EDJEFILE, GRP_LAYOUT_CHANNELINFO_LIST); - priv->current_channel = util_add_layout(priv->layout, GRP_CHANNELINFO); - if (!priv->current_channel) - goto error; - elm_object_part_content_set(priv->layout, - PART_CHANNELINFO_LIST_CURRENT, priv->current_channel); + evas_object_size_hint_weight_set(priv->base, + EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, priv->base); + elm_object_focus_allow_set(priv->base, EINA_TRUE); - priv->prev_channel = util_add_layout(priv->layout, - GRP_CHANNELINFO_SIMPLE); - if (!priv->prev_channel) - goto error; - elm_object_part_content_set(priv->layout, - PART_CHANNELINFO_LIST_PREV, priv->prev_channel); - - priv->lmgr = lmgr; + if (!_draw_channel_layout(priv)) { + _ERR("failed to create channel layout"); - layoutmgr_set_layout_data(lmgr, LAYOUT_CHANNELINFO_LIST, priv); + evas_object_del(priv->base); + free(priv); - return true; - -error: - _ERR("failed to create layout"); + return false; + } - if (priv->layout) - evas_object_del(priv->layout); - if (priv->prev_channel) - evas_object_del(priv->prev_channel); - if (priv->current_channel) - evas_object_del(priv->current_channel); - if (priv->next_channel) - evas_object_del(priv->next_channel); + priv->lmgr = lmgr; + layoutmgr_set_layout_data(lmgr, LAYOUT_CHANNELINFO_LIST, priv); - free(priv); + inputmgr_add_callback(priv->base, 0, &key_handler, priv); + elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, + SOURCE_ELM, _hide_finished_cb, priv); - return false; + return true; } static void _destroy(void *layout_data) @@ -215,7 +256,11 @@ static void _destroy(void *layout_data) if (priv->channel_info) tv_channel_del_info(priv->channel_info); - evas_object_del(priv->layout); + inputmgr_remove_callback(priv->base, &key_handler); + elm_layout_signal_callback_del(priv->base, SIGNAL_HIDE_FINISHED, + SOURCE_ELM, _hide_finished_cb); + + evas_object_del(priv->base); free(priv); } @@ -228,8 +273,9 @@ static void _show(void *layout_data) priv = layout_data; - elm_object_content_set(priv->base, priv->layout); - evas_object_show(priv->layout); + evas_object_show(priv->base); + + elm_object_focus_set(priv->base, EINA_TRUE); } static void _hide(void *layout_data) @@ -246,8 +292,7 @@ static void _hide(void *layout_data) priv->channel_info = NULL; } - evas_object_hide(priv->layout); - elm_object_content_unset(priv->base); + elm_layout_signal_emit(priv->base, SIGNAL_HIDE, SOURCE_ELM); } static void _update(void *layout_data, int type, void *data) diff --git a/src/layout_channelinfo_search.c b/src/layout_channelinfo_search.c index 6aaa01e..4267b7f 100644 --- a/src/layout_channelinfo_search.c +++ b/src/layout_channelinfo_search.c @@ -27,10 +27,10 @@ #define DIVIDER_WIDTH 536 #define DIVIDER_HEIGHT 1 -#define DIVIDER_COLOR_R 0 -#define DIVIDER_COLOR_G 0 -#define DIVIDER_COLOR_B 0 -#define DIVIDER_COLOR_A (255 * 0.1) +#define DIVIDER_COLOR_R 154 +#define DIVIDER_COLOR_G 154 +#define DIVIDER_COLOR_B 154 +#define DIVIDER_COLOR_A 255 struct _priv { Evas_Object *base; @@ -66,9 +66,23 @@ static void _tune_channel(void *data) static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { + int op; + if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) + !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + _tune_channel(data); + } else if (!strcmp(ev->keyname, KEY_BACK) || + !strcmp(ev->keyname, KEY_BACK_REMOTE) || + !strcmp(ev->keyname, KEY_EXIT)) { + viewmgr_hide_view(VIEW_CHANNELINFO); + } else if (!strcmp(ev->keyname, KEY_UP) || + !strcmp(ev->keyname, KEY_DOWN)) { + op = START_HIDE_TIMER; + viewmgr_update_view(VIEW_CHANNELINFO, + UPDATE_TYPE_TIMER, &op); + } } static void _mouse_down_cb(int id, void *data, Evas *e, Evas_Object *obj, @@ -77,9 +91,20 @@ static void _mouse_down_cb(int id, void *data, Evas *e, Evas_Object *obj, _tune_channel(data); } +static void _mouse_move_cb(int id, void *data, Evas *e, Evas_Object *obj, + Evas_Event_Mouse_Move *ev) +{ + int op; + + op = START_HIDE_TIMER; + viewmgr_update_view(VIEW_CHANNELINFO, + UPDATE_TYPE_TIMER, &op); +} + static input_handler channel_handler = { .key_down = _key_down_cb, .mouse_down = _mouse_down_cb, + .mouse_move = _mouse_move_cb, }; static void _release_channel_handler(Evas_Object *obj) @@ -156,6 +181,26 @@ static void _load_channel_list(struct _priv *priv, Eina_List *channel_list) } } +static bool _draw_channel_layout(struct _priv *priv) +{ + priv->scroll = util_add_scroller(priv->base, NULL); + if (!priv->scroll) { + _ERR("failed to create scroll"); + return false; + } + + priv->box = util_add_box(priv->scroll, false); + if (!priv->box) { + _ERR("failed to create box"); + evas_object_del(priv->scroll); + + return false; + } + elm_box_align_set(priv->box, 0.0, 0.5); + + return true; +} + static void _update_channel_list(struct _priv *priv) { Eina_List *channel_list; @@ -179,6 +224,7 @@ static void _update_channel_list(struct _priv *priv) static bool _create(layoutmgr *lmgr, void *data) { struct _priv *priv; + Evas_Object *win; priv = calloc(1, sizeof(*priv)); if (!priv) { @@ -186,35 +232,35 @@ static bool _create(layoutmgr *lmgr, void *data) return false; } - priv->base = layoutmgr_get_base(lmgr); + win = layoutmgr_get_base(lmgr); - priv->scroll = elm_scroller_add(priv->base); - if (!priv->scroll) { - _ERR("failed to create scroll"); - goto error; + priv->base = elm_layout_add(win); + if (!priv->base) { + _ERR("failed to create layout"); + free(priv); + + return false; } - evas_object_size_hint_weight_set(priv->scroll, + + elm_layout_file_set(priv->base, EDJEFILE, + GRP_LAYOUT_CHANNELINFO_SEARCH); + evas_object_size_hint_weight_set(priv->base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, priv->base); - priv->box = util_add_box(priv->scroll, false); - if (!priv->box) { - _ERR("failed to create box"); - goto error; + if (!_draw_channel_layout(priv)) { + _ERR("failed to create channel layout"); + + evas_object_del(priv->base); + free(priv); + + return false; } - elm_box_align_set(priv->box, 0.0, 0.5); priv->lmgr = lmgr; - layoutmgr_set_layout_data(lmgr, LAYOUT_CHANNELINFO_SEARCH, priv); return true; - -error: - evas_object_del(priv->scroll); - evas_object_del(priv->box); - free(priv); - - return false; } static void _destroy(void *layout_data) @@ -226,7 +272,9 @@ static void _destroy(void *layout_data) priv = layout_data; - evas_object_del(priv->scroll); + _release_channel_handler(priv->box); + + evas_object_del(priv->base); free(priv); } @@ -241,8 +289,7 @@ static void _show(void *layout_data) _update_channel_list(priv); - elm_object_content_set(priv->base, priv->scroll); - evas_object_show(priv->scroll); + evas_object_show(priv->base); } static void _hide(void *layout_data) @@ -254,8 +301,7 @@ static void _hide(void *layout_data) priv = layout_data; - elm_object_content_unset(priv->base); - evas_object_hide(priv->scroll); + evas_object_hide(priv->base); } static void _update(void *layout_data, int update_type, void *data) diff --git a/src/util.c b/src/util.c index 041d77b..272c63e 100644 --- a/src/util.c +++ b/src/util.c @@ -94,8 +94,7 @@ Evas_Object *util_add_scroller(Evas_Object *parent, const char *part) elm_scroller_policy_set(scroll, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); - if (part) - elm_object_part_content_set(parent, part, scroll); + elm_object_part_content_set(parent, part, scroll); evas_object_show(scroll); diff --git a/src/view_channelinfo.c b/src/view_channelinfo.c index 6a44cbf..20d40c4 100644 --- a/src/view_channelinfo.c +++ b/src/view_channelinfo.c @@ -60,48 +60,6 @@ static void _set_current_layout(struct _priv *priv, const char *layout_id) priv->current_layout = layout_id; } -static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, - Evas_Event_Key_Down *ev) -{ - struct _priv *priv; - int op; - - if (!data) { - _ERR("failed to get data"); - return; - } - - priv = data; - - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { - _set_current_layout(priv, LAYOUT_CHANNELINFO_SEARCH); - } else if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE) || - !strcmp(ev->keyname, KEY_EXIT)) { - viewmgr_hide_view(VIEW_CHANNELINFO); - } else { - op = START_HIDE_TIMER; - viewmgr_update_view(VIEW_CHANNELINFO, - UPDATE_TYPE_TIMER, &op); - } -} - -static void _mouse_move_cb(int id, void *data, Evas *e, Evas_Object *obj, - Evas_Event_Mouse_Move *ev) -{ - int op; - - op = START_HIDE_TIMER; - viewmgr_update_view(VIEW_CHANNELINFO, - UPDATE_TYPE_TIMER, &op); -} - -static input_handler key_handler = { - .key_down = _key_down_cb, - .mouse_move = _mouse_move_cb, -}; - static Eina_Bool _hide_timer(void *data) { struct _priv *priv; @@ -149,20 +107,7 @@ static Evas_Object *_create(Evas_Object *win, void *data) return NULL; } - priv->base = elm_layout_add(win); - if (!priv->base) { - _ERR("failed to create base object"); - free(priv); - return NULL; - } - elm_layout_file_set(priv->base, EDJEFILE, GRP_VIEW_CHANNELINFO); - elm_object_focus_allow_set(priv->base, EINA_TRUE); - - evas_object_size_hint_weight_set(priv->base, - EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_win_resize_object_add(win, priv->base); - - priv->lmgr = layoutmgr_create(priv->base); + priv->lmgr = layoutmgr_create(win); layoutmgr_add_layout(priv->lmgr, layout_channelinfo_get_lclass(), NULL); layoutmgr_add_layout(priv->lmgr, layout_channelinfo_list_get_lclass(), NULL); @@ -171,9 +116,7 @@ static Evas_Object *_create(Evas_Object *win, void *data) viewmgr_set_view_data(VIEW_CHANNELINFO, priv); - inputmgr_add_callback(priv->base, 0, &key_handler, priv); - - return priv->base; + return win; } static void _show(void *view_data) @@ -187,9 +130,6 @@ static void _show(void *view_data) priv = view_data; - evas_object_show(priv->base); - elm_object_focus_set(priv->base, EINA_TRUE); - if (!priv->current_layout) _set_current_layout(priv, LAYOUT_CHANNELINFO); } @@ -206,8 +146,6 @@ static void _hide(void *view_data) priv = view_data; _hide_current_layout(priv); - - evas_object_hide(priv->base); } static void _destroy(void *view_data) @@ -226,10 +164,6 @@ static void _destroy(void *view_data) layoutmgr_remove_layout(priv->lmgr, LAYOUT_CHANNELINFO_SEARCH); layoutmgr_destroy(priv->lmgr); - inputmgr_remove_callback(priv->base, &key_handler); - - evas_object_del(priv->base); - free(priv); } -- 2.7.4 From a1334e19feac5e2c29323e84625d33b47257cd59 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Wed, 16 Sep 2015 13:54:21 +0900 Subject: [PATCH 06/16] Add action menu show/hide animation Change-Id: I15c3de46050f0635811b89ccc51d0934459f6a1a Signed-off-by: jinwoo.shin --- data/view/action_menu.edc | 25 ++++++++++++++++++++++++- data/view/channelinfo.edc | 10 +++++----- include/define.h | 3 +++ src/view_action_menu.c | 17 ++++++++++++++++- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/data/view/action_menu.edc b/data/view/action_menu.edc index 1905e50..5d02e59 100644 --- a/data/view/action_menu.edc +++ b/data/view/action_menu.edc @@ -35,9 +35,14 @@ group { color, 255 255 255 255; rel1.relative, 1.0 0.0; min, 500 0; - align, 1.0 0.0; + align, 0.0 0.0; fixed, 1 1; } + description { + state, "show" 0.0; + inherit, "default" 0.0; + align, 1.0 0.0; + } } part { @@ -367,6 +372,24 @@ group { programs { program { + signal, SIGNAL_SHOW; + action, STATE_SET "show" 0.0; + target, "menu_area"; + transition, CUBIC_BEZIER 0.667 TRANSITION_EASE_IN_OUT; + } + program { + signal, SIGNAL_HIDE; + source, SOURCE_ELM; + action, STATE_SET "default" 0.0; + target, "menu_area"; + transition, CUBIC_BEZIER 0.334 TRANSITION_EASE_OUT; + after, "hide_finished"; + } + program { + name, "hide_finished"; + action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; + } + program { name, "no_favorite"; signal, SIGNAL_NO_FAVORITE; source, SOURCE_ELM; diff --git a/data/view/channelinfo.edc b/data/view/channelinfo.edc index 8b7ece3..f9ce6a8 100644 --- a/data/view/channelinfo.edc +++ b/data/view/channelinfo.edc @@ -64,14 +64,14 @@ group { signal, SIGNAL_SHOW; action, STATE_SET "show" 0.0; target, PART_CONTENT; - transition, CUBIC_BEZIER 0.5 0.45 0.03 0.41 1.0; + transition, CUBIC_BEZIER 0.5 TRANSITION_EASE_IN_OUT; } program { signal, SIGNAL_HIDE; source, SOURCE_ELM; action, STATE_SET "default" 0.0; target, PART_CONTENT; - transition, CUBIC_BEZIER 0.167 0.25 0.46 0.45 1.0; + transition, CUBIC_BEZIER 0.167 TRANSITION_EASE_OUT; after, "hide_finished"; } program { @@ -359,7 +359,7 @@ group { name, "show_current"; action, STATE_SET "show" 0.0; target, "clip_current"; - transition, CUBIC_BEZIER 0.334 0.45 0.03 0.41 1.0; + transition, CUBIC_BEZIER 0.334 TRANSITION_EASE_IN_OUT; } program { name, "show_other"; @@ -368,14 +368,14 @@ group { target, PART_CHANNELINFO_LIST_NEXT; target, "clip_prev"; target, PART_CHANNELINFO_LIST_PREV; - transition, CUBIC_BEZIER 0.401 0.45 0.03 0.41 1.0; + transition, CUBIC_BEZIER 0.401 TRANSITION_EASE_IN_OUT; } program { signal, SIGNAL_HIDE; source, SOURCE_ELM; action, STATE_SET "default" 0.0; target, "bg"; - transition, CUBIC_BEZIER 0.167 0.25 0.46 0.45 1.0; + transition, CUBIC_BEZIER 0.167 TRANSITION_EASE_OUT; sequence { action, STATE_SET "default" 0.0; target, "clip_next"; diff --git a/include/define.h b/include/define.h index ac98f3d..b919392 100644 --- a/include/define.h +++ b/include/define.h @@ -66,6 +66,9 @@ #define COLOR_NOFAVORITE_BG 229 229 229 255 #define COLOR_NOFAVORITE_TEXT 0 0 0 178 +#define TRANSITION_EASE_IN_OUT 0.45 0.03 0.41 1.0 +#define TRANSITION_EASE_OUT 0.25 0.46 0.45 1.0 + #define IMAGE_FAV_NOR IMAGEDIR"/btn_menu_favorite_nor.png" #define IMAGE_FAV_FOC IMAGEDIR"/btn_menu_favorite_foc.png" #define IMAGE_FAV_SEL IMAGEDIR"/btn_menu_favorite_sel.png" diff --git a/src/view_action_menu.c b/src/view_action_menu.c index 6c21921..119708b 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -605,6 +605,19 @@ static void _draw_view_content(struct _priv *priv) _ERR("Draw bottom area failed."); } +static void _hide_finished_cb(void *data, Evas_Object *obj, + const char *emission, const char *source) +{ + struct _priv *priv; + + if (!data) + return; + + priv = data; + + evas_object_hide(priv->base); +} + static Evas_Object *_create(Evas_Object *win, void *data) { struct _priv *priv; @@ -645,6 +658,8 @@ static Evas_Object *_create(Evas_Object *win, void *data) _draw_view_content(priv); inputmgr_add_callback(priv->base, 0, &key_handler, priv); + elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, + SOURCE_ELM, _hide_finished_cb, priv); return base; } @@ -678,7 +693,7 @@ static void _hide(void *data) } priv = data; - evas_object_hide(priv->base); + elm_layout_signal_emit(priv->base, SIGNAL_HIDE, SOURCE_ELM); } static void _destroy(void *data) -- 2.7.4 From 8bbcaa610b7952edf0f3058b0099d874c1cd71b9 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Wed, 16 Sep 2015 14:25:04 +0900 Subject: [PATCH 07/16] modify key values as key_define Change-Id: If3e317a0ff95d5acb98176afdb94cca4d2e704ec Signed-off-by: Minkyu Kang --- src/layout_channelinfo.c | 5 ++--- src/layout_channelinfo_list.c | 12 ++++-------- src/layout_channelinfo_search.c | 5 ++--- src/main.c | 8 ++++---- src/view_action_menu.c | 9 +++------ src/view_channelinfo.c | 11 +++-------- src/view_channelnumber.c | 6 ++---- 7 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/layout_channelinfo.c b/src/layout_channelinfo.c index 6226ae0..1f28e94 100644 --- a/src/layout_channelinfo.c +++ b/src/layout_channelinfo.c @@ -76,10 +76,9 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE) || - !strcmp(ev->keyname, KEY_EXIT)) { + !strcmp(ev->keyname, KEY_ESC) || + !strcmp(ev->keyname, KEY_EXIT)) viewmgr_hide_view(VIEW_CHANNELINFO); - } } static void _hide_finished_cb(void *data, Evas_Object *obj, diff --git a/src/layout_channelinfo_list.c b/src/layout_channelinfo_list.c index 760d565..d64743c 100644 --- a/src/layout_channelinfo_list.c +++ b/src/layout_channelinfo_list.c @@ -178,7 +178,7 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE) || + !strcmp(ev->keyname, KEY_ESC) || !strcmp(ev->keyname, KEY_EXIT)) { viewmgr_hide_view(VIEW_CHANNELINFO); } @@ -315,15 +315,13 @@ static void _update(void *layout_data, int type, void *data) return; } - if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE)) { + if (!strcmp(ev->keyname, KEY_CHANNELUP)) { r = _set_next_channel(priv, CHANNEL_NEXT); if (r < 0) _ERR("failed to set next channel"); else _update_channel_info(priv); - } else if (!strcmp(ev->keyname, KEY_CHANNELDOWN) || - !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) { + } else if (!strcmp(ev->keyname, KEY_CHANNELDOWN)) { r = _set_next_channel(priv, CHANNEL_PREV); if (r < 0) _ERR("failed to set prev channel"); @@ -339,9 +337,7 @@ static void _update(void *layout_data, int type, void *data) } if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE) || - !strcmp(ev->keyname, KEY_CHANNELDOWN) || - !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) { + !strcmp(ev->keyname, KEY_CHANNELDOWN)) { if (!priv->channel_info) { _ERR("failed to get channel info"); return; diff --git a/src/layout_channelinfo_search.c b/src/layout_channelinfo_search.c index 4267b7f..bd89866 100644 --- a/src/layout_channelinfo_search.c +++ b/src/layout_channelinfo_search.c @@ -68,13 +68,12 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, { int op; - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { + if (!strcmp(ev->keyname, KEY_ENTER)) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; _tune_channel(data); } else if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE) || + !strcmp(ev->keyname, KEY_ESC) || !strcmp(ev->keyname, KEY_EXIT)) { viewmgr_hide_view(VIEW_CHANNELINFO); } else if (!strcmp(ev->keyname, KEY_UP) || diff --git a/src/main.c b/src/main.c index 4c74363..f73507d 100644 --- a/src/main.c +++ b/src/main.c @@ -56,9 +56,9 @@ static struct key_map g_kmap[] = { { VIEW_CHANNELINFO, { - KEY_ENTER, KEY_ENTER_REMOTE, - KEY_CHANNELUP, KEY_CHANNELUP_REMOTE, - KEY_CHANNELDOWN, KEY_CHANNELDOWN_REMOTE + KEY_ENTER, + KEY_CHANNELUP, + KEY_CHANNELDOWN } }, { @@ -72,7 +72,7 @@ static struct key_map g_kmap[] = { { VIEW_ACTION_MENU, { - KEY_MENU, KEY_MENU_REMOTE + KEY_MENU, KEY_CONTEXT_MENU } }, }; diff --git a/src/view_action_menu.c b/src/view_action_menu.c index 6c21921..a7d56b7 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -276,7 +276,7 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE)) + !strcmp(ev->keyname, KEY_ESC)) viewmgr_hide_view(VIEW_ACTION_MENU); ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; @@ -332,11 +332,8 @@ static void _button_clicked(Evas_Object *obj, int id, void *data) static void _button_key_up_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Up *ev) { - if (strcmp(ev->keyname, KEY_ENTER) && - strcmp(ev->keyname, KEY_ENTER_REMOTE)) - return; - - _button_clicked(obj, id, data); + if (!strcmp(ev->keyname, KEY_ENTER)) + _button_clicked(obj, id, data); } static void _button_mouse_up_cb(int id, void *data, Evas *e, diff --git a/src/view_channelinfo.c b/src/view_channelinfo.c index 20d40c4..610e5a3 100644 --- a/src/view_channelinfo.c +++ b/src/view_channelinfo.c @@ -195,17 +195,14 @@ static void _update(void *view_data, int type, void *data) return; } - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { + if (!strcmp(ev->keyname, KEY_ENTER)) { if (!priv->current_layout) _set_current_layout(priv, LAYOUT_CHANNELINFO); else _set_current_layout(priv, LAYOUT_CHANNELINFO_SEARCH); } else if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE) || - !strcmp(ev->keyname, KEY_CHANNELDOWN) || - !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) { + !strcmp(ev->keyname, KEY_CHANNELDOWN)) { if (priv->current_layout && !strcmp(priv->current_layout, LAYOUT_CHANNELINFO_SEARCH)) @@ -226,9 +223,7 @@ static void _update(void *view_data, int type, void *data) } if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE) || - !strcmp(ev->keyname, KEY_CHANNELDOWN) || - !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) { + !strcmp(ev->keyname, KEY_CHANNELDOWN)) { if (priv->current_layout && !strcmp(priv->current_layout, LAYOUT_CHANNELINFO_SEARCH)) diff --git a/src/view_channelnumber.c b/src/view_channelnumber.c index bf1ce0c..44971cd 100644 --- a/src/view_channelnumber.c +++ b/src/view_channelnumber.c @@ -43,9 +43,8 @@ static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!strcmp(ev->keyname, KEY_BACK) || - !strcmp(ev->keyname, KEY_BACK_REMOTE)) { + !strcmp(ev->keyname, KEY_ESC)) viewmgr_hide_view(VIEW_CHANNELNUMBER); - } } static input_handler key_handler = { @@ -113,8 +112,7 @@ static void _tune_channel(void *data) static void _channel_key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { - if (!strcmp(ev->keyname, KEY_ENTER) || - !strcmp(ev->keyname, KEY_ENTER_REMOTE)) { + if (!strcmp(ev->keyname, KEY_ENTER)) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; _tune_channel(data); -- 2.7.4 From 102671981c31d0e8f0a3c2da34395e40e7df9e4e Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Thu, 17 Sep 2015 08:37:16 +0900 Subject: [PATCH 08/16] version update: m1 Change-Id: I563f7b157ebc13ca62a7a40c42af043f206de26c Signed-off-by: Minkyu Kang --- packaging/org.tizen.live-tv.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/org.tizen.live-tv.spec b/packaging/org.tizen.live-tv.spec index 256fda5..101d908 100644 --- a/packaging/org.tizen.live-tv.spec +++ b/packaging/org.tizen.live-tv.spec @@ -1,6 +1,6 @@ Name: org.tizen.live-tv Summary: Live TV application for Tizen TV -Version: 0.1 +Version: 0.2 Release: 1 Group: Applications License: Apache-2.0 -- 2.7.4 From 730ebf24ebca441310443f6dfe7541bfedb663f3 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Fri, 18 Sep 2015 18:06:07 +0900 Subject: [PATCH 09/16] Update action menu layout - Supports action menu scrolling - Added more button on the bottom Change-Id: Ie91f1ca23802575b9ba1bbd3a58b7763faeda82d Signed-off-by: jinwoo.shin --- data/view/action_menu.edc | 276 ++++++++++++++++++++++------------------------ include/define.h | 7 +- include/strings.h | 1 + src/view_action_menu.c | 188 ++++++++++++++++++------------- 4 files changed, 250 insertions(+), 222 deletions(-) diff --git a/data/view/action_menu.edc b/data/view/action_menu.edc index 5d02e59..ff4b944 100644 --- a/data/view/action_menu.edc +++ b/data/view/action_menu.edc @@ -27,16 +27,27 @@ group { } } part { - name, "menu_area"; + name, "menu_bg"; type, RECT; scale, 1; description { state, "default" 0.0; color, 255 255 255 255; + rel1.to, PART_CONTENT; + rel2.to, PART_CONTENT; + } + } + + part { + name, PART_CONTENT; + type, SWALLOW; + scale, 1; + description { + state, "default" 0.0; rel1.relative, 1.0 0.0; min, 500 0; align, 0.0 0.0; - fixed, 1 1; + fixed, 1 0; } description { state, "show" 0.0; @@ -52,9 +63,9 @@ group { description { state, "default" 0.0; color, 0 0 0 25; - rel1.to, "menu_area"; + rel1.to, PART_CONTENT; rel2 { - to, "menu_area"; + to, PART_CONTENT; relative, 0.0 1.0; } min, 1 0; @@ -64,17 +75,82 @@ group { } part { - name, "padding.livetv.btn"; + name, "padding.channelinfo"; type, SPACER; scale, 1; description { state, "default" 0.0; - rel1.to, "menu_area"; + rel1.relative, 0.0 0.0; + rel2.relative, 0.0 0.0; + min, 40 40; + align, 0.0 0.0; + fixed, 1 1; + } + } + + part { + name, PART_CHANNELINFO; + type, SWALLOW; + scale, 1; + description { + state, "default" 0.0; + rel1 { + to, "padding.channelinfo"; + relative, 1.0 1.0; + } rel2 { - to, "menu_area"; - relative, 1.0 0.0; + to, "padding.channelinfo"; + relative, 1.0 1.0; } - min, 0 118; + min, 536 174; + align, 0.0 0.0; + fixed, 1 1; + } + } + + } + programs { + program { + signal, SIGNAL_SHOW; + action, STATE_SET "show" 0.0; + target, PART_CONTENT; + transition, CUBIC_BEZIER 0.667 TRANSITION_EASE_IN_OUT; + } + program { + signal, SIGNAL_HIDE; + source, SOURCE_ELM; + action, STATE_SET "default" 0.0; + target, PART_CONTENT; + transition, CUBIC_BEZIER 0.334 TRANSITION_EASE_OUT; + after, "hide_finished"; + } + program { + name, "hide_finished"; + action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; + } + } +} + +group { + name, GRP_ACTION_MENU_TOP; + parts { + part { + name, "area"; + type, SPACER; + scale, 1; + description { + state, "default" 0.0; + min, 500 346; + } + } + part { + name, "padding.livetv.btn"; + type, SPACER; + scale, 1; + description { + state, "default" 0.0; + rel2.relative, 1.0 0.0; + min, 0 120; align, 0.5 0.0; fixed, 0 1; } @@ -113,7 +189,7 @@ group { } rel2.to, "padding.livetv.btn"; min, 0 1; - align, 0.5 1.0; + align, 0.0 1.0; fixed, 0 1; } } @@ -124,16 +200,9 @@ group { scale, 1; description { state, "default" 0.0; - rel1 { - to, PART_MENU; - relative, 0.0 0.0; - } - rel2 { - to, PART_MENU; - relative, 1.0 1.0; - } + rel1.to, PART_MENU; + rel2.to, PART_MENU; align, 0.0 0.0; - fixed, 1 1; color, 224 224 224 255; } } @@ -146,14 +215,14 @@ group { state, "default" 0.0; rel1 { to, "padding.menu.divider.up"; - relative, 0.0 1.0; + relative, 0.5 1.0; } rel2 { to, "padding.menu.divider.up"; - relative, 0.0 1.0; + relative, 0.5 1.0; } - min, 500 0; - align, 0.0 0.0; + min, 500 126; + align, 0.5 0.0; fixed, 1 1; } } @@ -245,165 +314,80 @@ group { fixed, 1 1; } } + } +} +group { + name, GRP_ACTION_MENU_BOTTOM; + parts { part { - name, PART_FAVORITE; - type, SWALLOW; + name, "padding.more.btn"; + type, SPACER; scale, 1; description { state, "default" 0.0; - rel1 { - to, "padding.favorite.list"; - relative, 0.5 1.0; - } - rel2 { - to, "padding.favorite.list"; - relative, 0.5 1.0; - } - min, 440 0; - align, 0.5 0.0; - fixed, 1 1; + rel1.relative, 0.0 0.0; + rel2.relative, 1.0 0.0; + min, 0 116; + align, 0.0 0.0; + fixed, 1 0; } } part { - name, "padding.favorite.list_bottom"; - type, SPACER; + name, PART_MORE_BUTTON; + type, SWALLOW; scale, 1; description { state, "default" 0.0; rel1 { - to, "menu_area"; - relative, 0.0 1.0; + to, "padding.more.btn"; + relative, 0.5 0.5; } rel2 { - to, "menu_area"; - relative, 1.0 1.0; + to, "padding.more.btn"; + relative, 0.5 0.5; } - min, 0 32; - align, 0.0 1.0; + min, 184 60; + align, 0.5 0.5; fixed, 1 1; } } + } +} +group { + name, GRP_ACTION_MENU_NO_FAVORITE; + parts { part { name, "part.favorite.no_favorite"; type, RECT; scale, 1; description { state, "default" 0.0; - rel1 { - to, "padding.favorite.list"; - relative, 0.5 1.0; - } - rel2 { - to, "padding.favorite.list_bottom"; - relative, 0.5 0.0; - } - min, 440 0; + rel1.relative, 0.5 0.0; + rel2.relative, 0.5 0.0; + min, 440 616; align, 0.5 0.0; - fixed, 1 1; color, COLOR_NOFAVORITE_BG; - visible, 0; - } - description { - state, "no_favorite" 0.0; - inherit, "default" 0.0; - visible, 1; - } - - part { - name, "part.favorite.no_favorite.text"; - type, TEXT; - scale, 1; - description { - state, "default" 0.0; - text { - font, FONT_LIGHT; - size, 28; - align, 0.5 0.5; - text, STR_NOFAVORITE; - } - color, COLOR_NOFAVORITE_TEXT; - visible, 0; - } - description { - state, "no_favorite" 0.0; - inherit, "default" 0.0; - visible, 1; - } } } - part { - name, "padding.channelinfo"; - type, SPACER; - scale, 1; - description { - state, "default" 0.0; - rel1.relative, 0.0 0.0; - rel2.relative, 0.0 0.0; - min, 40 40; - align, 0.0 0.0; - fixed, 1 1; - } - } - - part { - name, PART_CHANNELINFO; - type, SWALLOW; + name, "part.favorite.no_favorite.text"; + type, TEXT; scale, 1; description { state, "default" 0.0; - rel1 { - to, "padding.channelinfo"; - relative, 1.0 1.0; - } - rel2 { - to, "padding.channelinfo"; - relative, 1.0 1.0; + rel1.to, "part.favorite.no_favorite"; + rel2.to, "part.favorite.no_favorite"; + text { + font, FONT_LIGHT; + size, 28; + align, 0.5 0.5; + text, STR_NOFAVORITE; } - min, 536 174; - align, 0.0 0.0; - fixed, 1 1; + color, COLOR_NOFAVORITE_TEXT; } } } - - programs { - program { - signal, SIGNAL_SHOW; - action, STATE_SET "show" 0.0; - target, "menu_area"; - transition, CUBIC_BEZIER 0.667 TRANSITION_EASE_IN_OUT; - } - program { - signal, SIGNAL_HIDE; - source, SOURCE_ELM; - action, STATE_SET "default" 0.0; - target, "menu_area"; - transition, CUBIC_BEZIER 0.334 TRANSITION_EASE_OUT; - after, "hide_finished"; - } - program { - name, "hide_finished"; - action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; - } - program { - name, "no_favorite"; - signal, SIGNAL_NO_FAVORITE; - source, SOURCE_ELM; - action, STATE_SET "no_favorite" 0.0; - target, "part.favorite.no_favorite"; - target, "part.favorite.no_favorite.text"; - } - program { - name, "favorite"; - signal, SIGNAL_FAVORITE; - action, STATE_SET "default" 0.0; - source, SOURCE_ELM; - target, "part.favorite.no_favorite"; - target, "part.favorite.no_favorite.text"; - } - } } diff --git a/include/define.h b/include/define.h index b919392..369ce08 100644 --- a/include/define.h +++ b/include/define.h @@ -130,10 +130,13 @@ #define VIEW_ACTION_MENU "VIEW_ACTION_MENU" #define GRP_VIEW_ACTION_MENU "grp.view.action_menu" +#define PART_CHANNELINFO "part.channelinfo" +#define GRP_ACTION_MENU_TOP "grp.action_menu_top" #define PART_TOP_BUTTON "part.top.button" #define PART_MENU "part.menu" -#define PART_FAVORITE "part.favorite" -#define PART_CHANNELINFO "part.channelinfo" +#define GRP_ACTION_MENU_BOTTOM "grp.action_menu_bottom" +#define PART_MORE_BUTTON "part.more.button" +#define GRP_ACTION_MENU_NO_FAVORITE "grp.action_menu_no_favorite" #define VIEW_PIN "VIEW_PIN" #define MESSAGE_SUCCESS "success" diff --git a/include/strings.h b/include/strings.h index d21f511..21aba70 100644 --- a/include/strings.h +++ b/include/strings.h @@ -25,6 +25,7 @@ #define STR_NOSIGNAL_TITLE "Weak or No Signal" #define STR_NOSIGNAL_TEXT "Check the antenna cable connection" #define STR_LIVETV "Live TV" +#define STR_BUTTON_MORE "More" #define STR_BUTTON_FAVORITE "Favorite" #define STR_BUTTON_LOCK "Lock" #define STR_BUTTON_UNLOCK "Unlock" diff --git a/src/view_action_menu.c b/src/view_action_menu.c index a116748..10362f1 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -28,6 +28,10 @@ #define BUTTON_BORDER 1 #define ITEMS_IN_ROW 4 #define FAVORITE_PADDING_Y 32 +#define FAVORITE_MAX 10 +#define SCROLLER_STEP_SIZE 334 + +#define TAG_FAVORITE "TAG_FAVORITE" #define STYLE_LIVETV_BTN "style.livetv.button" #define STYLE_ACTION_MENU_BTN "style.action.menu.button" @@ -39,6 +43,7 @@ enum _button_id { BUTTON_INVALID = -1, BUTTON_LIVETV, + BUTTON_MORE, BUTTON_FAV, BUTTON_LOCK, BUTTON_CHANNEL, @@ -54,6 +59,9 @@ enum _button_state { struct _priv { Evas_Object *win; Evas_Object *base; + Evas_Object *scroller; + Evas_Object *box; + Evas_Object *menu; Evas_Object *channel_info; Evas_Object *menu_btn[BUTTON_MAX]; Evas_Object *favorite; @@ -355,7 +363,7 @@ static void _button_mouse_move_cb(int id, void *data, Evas *e, Evas_Object *obj, static input_handler button_handler = { .key_up = _button_key_up_cb, .mouse_up = _button_mouse_up_cb, - .mouse_move = _button_mouse_move_cb + .mouse_move = _button_mouse_move_cb, }; static void _favorite_clicked_cb(int id, void *data, Evas_Object *obj) @@ -389,26 +397,28 @@ static void _update_favorite(struct _priv *priv) { Eina_List *channel_list, *l; const struct tv_channel_info *channel_info; - Evas_Object *btn, *obj; + Evas_Object *btn, *no_favorite; char buf[BUF_MAX]; int i; channel_list = tv_channel_get_favorite_list(); - i = 0; - while ((obj = elm_table_child_get(priv->favorite, 0, i++))) - inputmgr_remove_callback(obj, &favorite_handler); - - elm_table_clear(priv->favorite, EINA_TRUE); + inputmgr_remove_all_by_tag(TAG_FAVORITE); + elm_box_clear(priv->favorite); if (!channel_list) { - elm_object_signal_emit(priv->base, - SIGNAL_NO_FAVORITE, SOURCE_ELM); + no_favorite = util_add_layout(priv->favorite, + GRP_ACTION_MENU_NO_FAVORITE); + if (!no_favorite) { + _ERR("failed to create no favorite layout"); + return; + } + + elm_box_pack_end(priv->favorite, no_favorite); + return; } - elm_object_signal_emit(priv->base, SIGNAL_FAVORITE, SOURCE_ELM); - i = 0; EINA_LIST_FOREACH(channel_list, l, channel_info) { if (channel_info->channel_minor > 0 && @@ -421,18 +431,22 @@ static void _update_favorite(struct _priv *priv) snprintf(buf, sizeof(buf), "%lu %s", channel_info->channel_major, channel_info->channel_name); - btn = util_add_button(priv->base, NULL, buf, + btn = util_add_button(priv->menu, NULL, buf, STYLE_ACTION_MENU_FAVORITE); if (!btn) { - _ERR("Add button failed."); + _ERR("failed to create favorite item"); continue; } util_add_icon(btn, IMAGE_FAVORITE_DEFAULT, PART_CONTENT); inputmgr_add_callback(btn, channel_info->service_id, &favorite_handler, NULL); + inputmgr_set_tags(btn, TAG_FAVORITE); + + elm_box_pack_end(priv->favorite, btn); - elm_table_pack(priv->favorite, btn, 0, i++, 1, 1); + if (++i == FAVORITE_MAX) + break; } tv_channel_del_list(channel_list); @@ -455,7 +469,7 @@ static bool _draw_channel_info(struct _priv *priv) layout = util_add_layout(priv->base, GRP_CHANNELINFO); if (!layout) { - _ERR("Add layout failed."); + _ERR("failed to create channel info layout"); return false; } @@ -466,43 +480,27 @@ static bool _draw_channel_info(struct _priv *priv) return true; } -static bool _draw_top_area(struct _priv *priv) -{ - Evas_Object *btn; - - btn = util_add_button(priv->base, - PART_TOP_BUTTON, STR_LIVETV, STYLE_LIVETV_BTN); - if (!btn) { - _ERR("Add button failed."); - return false; - } - - elm_object_disabled_set(btn, EINA_TRUE); - - return true; -} - -static bool _draw_menu_area(struct _priv *priv) +static bool _draw_action_area(struct _priv *priv) { Evas_Object *table, *btn; int i, row, col; - table = elm_table_add(priv->base); + table = elm_table_add(priv->menu); if (!table) { - _ERR("Add table failed."); + _ERR("failed to create action table"); return false; } elm_table_padding_set(table, BUTTON_BORDER, BUTTON_BORDER); evas_object_show(table); - elm_object_part_content_set(priv->base, PART_MENU, table); + elm_object_part_content_set(priv->menu, PART_MENU, table); i = 0; while (buttons[i].id != BUTTON_INVALID && i < BUTTON_MAX) { - btn = util_add_button(priv->base, NULL, + btn = util_add_button(priv->menu, NULL, buttons[i].data[UNTOGGLE].text, buttons[i].style); if (!btn) { - _ERR("Add button failed."); + _ERR("failed to create action button"); evas_object_del(table); return false; } @@ -537,16 +535,11 @@ static bool _draw_menu_area(struct _priv *priv) i++; } - elm_object_focus_next_object_set(priv->menu_btn[0], - priv->menu_btn[i - 1], ELM_FOCUS_LEFT); - elm_object_focus_next_object_set(priv->menu_btn[i - 1], - priv->menu_btn[0], ELM_FOCUS_RIGHT); - while (col + 1 != ITEMS_IN_ROW) { - btn = util_add_button(priv->base, NULL, NULL, + btn = util_add_button(priv->menu, NULL, NULL, STYLE_ACTION_MENU_BTN); if (!btn) { - _ERR("Add button failed."); + _ERR("failed to create action button"); evas_object_del(table); return false; } @@ -563,20 +556,66 @@ static bool _draw_menu_area(struct _priv *priv) return true; } +static bool _draw_top_area(struct _priv *priv) +{ + Evas_Object *layout, *btn; + + layout = util_add_layout(priv->box, GRP_ACTION_MENU_TOP); + if (!layout) { + _ERR("failed to create menu layout"); + return false; + } + elm_box_pack_end(priv->box, layout); + + btn = util_add_button(layout, + PART_TOP_BUTTON, STR_LIVETV, STYLE_LIVETV_BTN); + if (!btn) { + _ERR("failed to create live button"); + return false; + } + + elm_object_disabled_set(btn, EINA_TRUE); + + priv->menu = layout; + + return _draw_action_area(priv); +} + +static bool _draw_favorite_area(struct _priv *priv) +{ + Evas_Object *box; + + box = elm_box_add(priv->box); + if (!box) { + _ERR("failed to create favorite box"); + return false; + } + elm_box_padding_set(box, 0, FAVORITE_PADDING_Y); + evas_object_show(box); + elm_box_pack_end(priv->box, box); + + priv->favorite = box; + + return true; +} + static bool _draw_bottom_area(struct _priv *priv) { - Evas_Object *table; + Evas_Object *layout, *btn; - table = elm_table_add(priv->base); - if (!table) { - _ERR("Add table failed."); + layout = util_add_layout(priv->box, GRP_ACTION_MENU_BOTTOM); + if (!layout) { + _ERR("failed to create menu layout"); return false; } - elm_table_padding_set(table, 0, FAVORITE_PADDING_Y); - evas_object_show(table); - elm_object_part_content_set(priv->base, PART_FAVORITE, table); + elm_box_pack_end(priv->box, layout); - priv->favorite = table; + btn = util_add_button(layout, + PART_MORE_BUTTON, STR_BUTTON_MORE, STYLE_LIVETV_BTN); + if (!btn) { + _ERR("failed to create more button"); + return false; + } return true; } @@ -584,22 +623,22 @@ static bool _draw_bottom_area(struct _priv *priv) static void _draw_view_content(struct _priv *priv) { if (!_draw_channel_info(priv)) { - _ERR("Draw channel info failed."); + _ERR("failed to draw channel info"); return; } if (!_draw_top_area(priv)) { - _ERR("Draw top area failed."); + _ERR("failed to draw top"); return; } - if (!_draw_menu_area(priv)) { - _ERR("Draw menu area failed."); + if (!_draw_favorite_area(priv)) { + _ERR("failed to draw favorite"); return; } if (!_draw_bottom_area(priv)) - _ERR("Draw bottom area failed."); + _ERR("failed to draw bottom"); } static void _hide_finished_cb(void *data, Evas_Object *obj, @@ -618,16 +657,16 @@ static void _hide_finished_cb(void *data, Evas_Object *obj, static Evas_Object *_create(Evas_Object *win, void *data) { struct _priv *priv; - Evas_Object *base; + Evas_Object *base, *scroller, *box; if (!win) { - _ERR("Get window object failed."); + _ERR("failed to get win object"); return NULL; } priv = calloc(1, sizeof(*priv)); if (!priv) { - _ERR("Calloc failed."); + _ERR("failed to allocate priv"); return NULL; } @@ -642,18 +681,20 @@ static Evas_Object *_create(Evas_Object *win, void *data) EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(win, base); + scroller = util_add_scroller(base, NULL); + elm_scroller_step_size_set(scroller, 0, SCROLLER_STEP_SIZE); + + box = util_add_box(scroller, NULL); + elm_box_align_set(box, 0.5, 0.0); + + priv->box = box; + priv->scroller = scroller; priv->base = base; priv->win = win; - if (!viewmgr_set_view_data(VIEW_ACTION_MENU, priv)) { - _ERR("Set view data failed."); - evas_object_del(base); - free(priv); - return NULL; - } - _draw_view_content(priv); + viewmgr_set_view_data(VIEW_ACTION_MENU, priv); inputmgr_add_callback(priv->base, 0, &key_handler, priv); elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, SOURCE_ELM, _hide_finished_cb, priv); @@ -666,7 +707,7 @@ static void _show(void *data) struct _priv *priv; if (!data) { - _ERR("Get data failed."); + _ERR("failed to get data"); return; } priv = data; @@ -675,6 +716,8 @@ static void _show(void *data) _update_menu(priv); _update_favorite(priv); + elm_scroller_region_show(priv->scroller, 0, 0, 0, 0); + evas_object_show(priv->base); elm_object_focus_set(priv->menu_btn[0], EINA_TRUE); @@ -685,7 +728,7 @@ static void _hide(void *data) struct _priv *priv; if (!data) { - _ERR("Get data failed."); + _ERR("failed to get data"); return; } priv = data; @@ -696,11 +739,10 @@ static void _hide(void *data) static void _destroy(void *data) { struct _priv *priv; - Evas_Object *obj; int i; if (!data) { - _ERR("Get data failed."); + _ERR("failed to get data"); return; } priv = data; @@ -713,9 +755,7 @@ static void _destroy(void *data) i++; } - i = 0; - while ((obj = elm_table_child_get(priv->favorite, 0, i++))) - inputmgr_remove_callback(obj, &favorite_handler); + inputmgr_remove_all_by_tag(TAG_FAVORITE); evas_object_del(priv->base); -- 2.7.4 From c580e3fc89378fc0cf395f67fd360f10332b1304 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Fri, 18 Sep 2015 19:11:12 +0900 Subject: [PATCH 10/16] Fix wrong while statement Change-Id: Ib939327c8281d5c6af517f80aa146bf08430b14d Signed-off-by: jinwoo.shin --- src/view_action_menu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/view_action_menu.c b/src/view_action_menu.c index 10362f1..76265fe 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -457,7 +457,7 @@ static void _update_menu(struct _priv *priv) int i; i = 0; - while (buttons[i].id != BUTTON_INVALID && i < BUTTON_MAX) { + while (i < BUTTON_MAX && buttons[i].id != BUTTON_INVALID) { _update_button_state(priv->menu_btn[i], &buttons[i]); i++; } @@ -495,7 +495,7 @@ static bool _draw_action_area(struct _priv *priv) elm_object_part_content_set(priv->menu, PART_MENU, table); i = 0; - while (buttons[i].id != BUTTON_INVALID && i < BUTTON_MAX) { + while (i < BUTTON_MAX && buttons[i].id != BUTTON_INVALID) { btn = util_add_button(priv->menu, NULL, buttons[i].data[UNTOGGLE].text, buttons[i].style); @@ -750,7 +750,7 @@ static void _destroy(void *data) inputmgr_remove_callback(priv->base, &key_handler); i = 0; - while (priv->menu_btn[i] && i < BUTTON_MAX) { + while (i < BUTTON_MAX && priv->menu_btn[i]) { inputmgr_remove_callback(priv->menu_btn[i], &button_handler); i++; } -- 2.7.4 From f936f9376b8f813f13a791e36dc695fe8b794290 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Mon, 21 Sep 2015 18:33:16 +0900 Subject: [PATCH 11/16] Change font to BreezeSans Change-Id: Id6cd7255e2cb8283b227c6a9b0bdadd476690aed Signed-off-by: jinwoo.shin --- data/widget/notify.edc | 2 +- include/define.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/widget/notify.edc b/data/widget/notify.edc index f574396..369bcf4 100644 --- a/data/widget/notify.edc +++ b/data/widget/notify.edc @@ -132,7 +132,7 @@ group { styles { style { name: "toast_style"; - base: "font=TizenSans:style=Light font_size=28 align=center color=#515151"; + base: "font=BreezeSans:style=Light font_size=28 align=center color=#515151"; tag: "br" "\n"; tag: "tab" "\t"; } diff --git a/include/define.h b/include/define.h index 369ce08..0012083 100644 --- a/include/define.h +++ b/include/define.h @@ -51,9 +51,9 @@ #define SIGNAL_HIDE_FINISHED "elm,action,hide,finished" #define SIGNAL_TIMEOUT "timeout" -#define FONT_REGULAR "TizenSans" -#define FONT_LIGHT "TizenSans:style=Light" -#define FONT_BOLD "TizenSans:style=Bold" +#define FONT_REGULAR "BreezeSans" +#define FONT_LIGHT "BreezeSans:style=Light" +#define FONT_BOLD "BreezeSans:style=Bold" #define COLOR_BG_NORMAL 255 255 255 255 #define COLOR_BG_FOCUSED 0 119 246 255 -- 2.7.4 From a73bb7a2bb3d14225df86c329038008ba08f107e Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Mon, 21 Sep 2015 19:04:28 +0900 Subject: [PATCH 12/16] Add default focus for key event Change-Id: Iaf13892c902434d7dcf87ec35b450b20cdeeacfa Signed-off-by: jinwoo.shin --- src/view_channelnumber.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/view_channelnumber.c b/src/view_channelnumber.c index 44971cd..310ed2a 100644 --- a/src/view_channelnumber.c +++ b/src/view_channelnumber.c @@ -323,6 +323,7 @@ static Evas_Object *_create(Evas_Object *win, void *data) evas_object_size_hint_weight_set(priv->base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(win, priv->base); + elm_object_focus_allow_set(priv->base, EINA_TRUE); scroll = util_add_scroller(priv->base, PART_CHANNELNUMBER_LIST); if (!scroll) { @@ -374,6 +375,7 @@ static void _show(void *view_data) evas_object_show(priv->base); viewmgr_hide_view(VIEW_CHANNELINFO); + elm_object_focus_set(priv->base, EINA_TRUE); } static void _hide(void *view_data) -- 2.7.4 From a535d1d699ebe7d72f760dde3b4c11f97b969117 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Mon, 21 Sep 2015 19:20:22 +0900 Subject: [PATCH 13/16] Update action menu - Launch favorite when user press more button - Set tag on action menu input callbacks to delete them Change-Id: I3e9a768418db8d7949935aeb03290d05dd793abc Signed-off-by: jinwoo.shin --- org.tizen.live-tv.xml.in | 3 ++ src/view_action_menu.c | 86 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/org.tizen.live-tv.xml.in b/org.tizen.live-tv.xml.in index 5c8c0fa..7727803 100644 --- a/org.tizen.live-tv.xml.in +++ b/org.tizen.live-tv.xml.in @@ -7,4 +7,7 @@ @DESKTOP_ICON@ + + http://tizen.org/privilege/appmanager.launch + diff --git a/src/view_action_menu.c b/src/view_action_menu.c index 76265fe..c998f29 100644 --- a/src/view_action_menu.c +++ b/src/view_action_menu.c @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include "define.h" #include "util.h" @@ -32,6 +34,7 @@ #define SCROLLER_STEP_SIZE 334 #define TAG_FAVORITE "TAG_FAVORITE" +#define KEY_BUTTON "KEY_BUTTON" #define STYLE_LIVETV_BTN "style.livetv.button" #define STYLE_ACTION_MENU_BTN "style.action.menu.button" @@ -320,21 +323,67 @@ static void _update_button_state(Evas_Object *obj, struct _button *button) } } -static void _button_clicked(Evas_Object *obj, int id, void *data) +static void _launch_favorite(void) { - struct _button *button; + app_control_h app_ctrl; + int r; - if (!data) { - _ERR("failed to get data"); + r = app_control_create(&app_ctrl); + if (r != APP_CONTROL_ERROR_NONE) { + _ERR("failed to create app control handle"); return; } - button = data; + r = app_control_set_operation(app_ctrl, APP_CONTROL_OPERATION_DEFAULT); + if (r != APP_CONTROL_ERROR_NONE) { + _ERR("failed to set app control operation"); + app_control_destroy(app_ctrl); + return; + } + + r = app_control_set_app_id(app_ctrl, APP_ID_FAVORITE); + if (r != APP_CONTROL_ERROR_NONE) { + _ERR("failed to set app control app id"); + app_control_destroy(app_ctrl); + return; + } - if (button->clicked) - button->clicked(); + r = app_control_send_launch_request(app_ctrl, NULL, NULL); + if (r != APP_CONTROL_ERROR_NONE) { + _ERR("failed to send app control launch request"); + app_control_destroy(app_ctrl); + return; + } - _update_button_state(obj, button); + app_control_destroy(app_ctrl); +} + +static void _button_clicked(Evas_Object *obj, int id, void *data) +{ + struct _button *button; + + switch (id) { + case BUTTON_MORE: + _launch_favorite(); + + viewmgr_hide_view(VIEW_ACTION_MENU); + break; + case BUTTON_FAV: + case BUTTON_LOCK: + case BUTTON_CHANNEL: + button = evas_object_data_get(obj, KEY_BUTTON); + if (!button) { + _ERR("failed to get button"); + return; + } + + if (button->clicked) + button->clicked(); + + _update_button_state(obj, button); + + break; + } } static void _button_key_up_cb(int id, void *data, Evas *e, Evas_Object *obj, @@ -441,7 +490,7 @@ static void _update_favorite(struct _priv *priv) util_add_icon(btn, IMAGE_FAVORITE_DEFAULT, PART_CONTENT); inputmgr_add_callback(btn, channel_info->service_id, &favorite_handler, NULL); - inputmgr_set_tags(btn, TAG_FAVORITE); + inputmgr_set_tags(btn, TAG_FAVORITE, VIEW_ACTION_MENU); elm_box_pack_end(priv->favorite, btn); @@ -523,8 +572,10 @@ static bool _draw_action_area(struct _priv *priv) PART_ICON_1_SELECTED); util_add_icon(btn, buttons[i].data[TOGGLE].disabled, PART_ICON_1_DISABLED); + evas_object_data_set(btn, KEY_BUTTON, &buttons[i]); inputmgr_add_callback(btn, buttons[i].id, - &button_handler, &buttons[i]); + &button_handler, priv); + inputmgr_set_tags(btn, VIEW_ACTION_MENU); col = i % ITEMS_IN_ROW; row = i / ITEMS_IN_ROW; @@ -616,6 +667,9 @@ static bool _draw_bottom_area(struct _priv *priv) _ERR("failed to create more button"); return false; } + inputmgr_add_callback(btn, BUTTON_MORE, + &button_handler, priv); + inputmgr_set_tags(btn, VIEW_ACTION_MENU); return true; } @@ -696,6 +750,7 @@ static Evas_Object *_create(Evas_Object *win, void *data) viewmgr_set_view_data(VIEW_ACTION_MENU, priv); inputmgr_add_callback(priv->base, 0, &key_handler, priv); + inputmgr_set_tags(priv->base, VIEW_ACTION_MENU); elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, SOURCE_ELM, _hide_finished_cb, priv); @@ -739,7 +794,6 @@ static void _hide(void *data) static void _destroy(void *data) { struct _priv *priv; - int i; if (!data) { _ERR("failed to get data"); @@ -747,15 +801,7 @@ static void _destroy(void *data) } priv = data; - inputmgr_remove_callback(priv->base, &key_handler); - - i = 0; - while (i < BUTTON_MAX && priv->menu_btn[i]) { - inputmgr_remove_callback(priv->menu_btn[i], &button_handler); - i++; - } - - inputmgr_remove_all_by_tag(TAG_FAVORITE); + inputmgr_remove_all_by_tag(VIEW_ACTION_MENU); evas_object_del(priv->base); -- 2.7.4 From 7a786bb412a9e777f3664404d600ee3487b2abd4 Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Tue, 22 Sep 2015 14:33:52 +0900 Subject: [PATCH 14/16] Do not add to recent when live tv is resumed Change-Id: I4c503697a8bd1719d971399299d5ea2a5baf3398 Signed-off-by: jinwoo.shin --- src/main.c | 2 +- src/tv.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index f73507d..6bc6797 100644 --- a/src/main.c +++ b/src/main.c @@ -310,9 +310,9 @@ static bool _create(void *data) return false; } + viewmgr_add_view(view_error_get_vclass(), NULL); viewmgr_add_view(view_channelinfo_get_vclass(), NULL); viewmgr_add_view(view_channelnumber_get_vclass(), NULL); - viewmgr_add_view(view_error_get_vclass(), NULL); viewmgr_add_view(view_action_menu_get_vclass(), NULL); viewmgr_add_view(view_pin_get_vclass(), NULL); diff --git a/src/tv.c b/src/tv.c index 418d579..d764ae5 100644 --- a/src/tv.c +++ b/src/tv.c @@ -714,8 +714,6 @@ int tv_channel_tune(void) return -1; } - _tv_channel_add_history(service_id); - g_tv_info.viewing_locked_channel = -1; return 0; -- 2.7.4 From ca5e9794cf61e4924e478dfd396b5073aa8b7def Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Thu, 24 Sep 2015 11:25:04 +0900 Subject: [PATCH 15/16] Add channel prev/next animation Change-Id: Ia08c1738821418858e46b91996e9b23ea317c9b5 Signed-off-by: jinwoo.shin --- data/view/channelinfo.edc | 100 +++++++++++++++++++- include/define.h | 3 + src/layout_channelinfo_list.c | 215 +++++++++++++++++++++++++++++------------- 3 files changed, 250 insertions(+), 68 deletions(-) diff --git a/data/view/channelinfo.edc b/data/view/channelinfo.edc index f9ce6a8..6ead49c 100644 --- a/data/view/channelinfo.edc +++ b/data/view/channelinfo.edc @@ -177,12 +177,15 @@ group { state, "default" 0.0; rel1 { to, "clip_next"; + relative, 0.0 0.5; offset, 0 20; } rel2 { to, "clip_next"; + relative, 1.0 0.5; offset, 0 20; } + align, 0.0 0.5; } description { state, "show" 0.0; @@ -190,6 +193,20 @@ group { rel1.offset, 0 0; rel2.offset, 0 0; } + description { + state, "up" 0.0; + inherit, "show" 0.0; + rel1.relative, 0.0 0.0; + rel2.relative, 1.0 0.0; + align, 0.0 0.0; + } + description { + state, "down" 0.0; + inherit, "show" 0.0; + rel1.relative, 0.0 1.0; + rel2.relative, 1.0 1.0; + align, 0.0 1.0; + } } part { name, "padding.current_channel"; @@ -239,8 +256,29 @@ group { clip_to, "clip_current"; description { state, "default" 0.0; - rel1.to, "clip_current"; - rel2.to, "clip_current"; + rel1 { + to, "clip_current"; + relative, 0.0 0.5; + } + rel2 { + to, "clip_current"; + relative, 1.0 0.5; + } + align, 0.0 0.5; + } + description { + state, "up" 0.0; + inherit, "default" 0.0; + rel1.relative, 0.0 0.0; + rel2.relative, 1.0 0.0; + align, 0.0 0.0; + } + description { + state, "down" 0.0; + inherit, "default" 0.0; + rel1.relative, 0.0 1.0; + rel2.relative, 1.0 1.0; + align, 0.0 1.0; } } part { @@ -249,11 +287,11 @@ group { description { state, "default" 0.0; rel1 { - to, PART_CHANNELINFO_LIST_CURRENT; + to, "clip_current"; relative, 0.5 1.0; } rel2 { - to, PART_CHANNELINFO_LIST_CURRENT; + to, "clip_current"; relative, 0.5 1.0; } min, 0 32; @@ -293,12 +331,15 @@ group { state, "default" 0.0; rel1 { to, "clip_prev"; + relative, 0.0 0.5; offset, 0 -20; } rel2 { to, "clip_prev"; + relative, 1.0 0.5; offset, 0 -20; } + align, 0.0 0.5; } description { state, "show" 0.0; @@ -306,6 +347,20 @@ group { rel1.offset, 0 0; rel2.offset, 0 0; } + description { + state, "up" 0.0; + inherit, "show" 0.0; + rel1.relative, 0.0 0.0; + rel2.relative, 1.0 0.0; + align, 0.0 0.0; + } + description { + state, "down" 0.0; + inherit, "show" 0.0; + rel1.relative, 0.0 1.0; + rel2.relative, 1.0 1.0; + align, 0.0 1.0; + } } part { name, "padding.navigation_down"; @@ -387,6 +442,42 @@ group { action, SIGNAL_EMIT SIGNAL_HIDE_FINISHED SOURCE_ELM; } } + program { + signal, SIGNAL_ANIM_MOVE_UP; + source, SOURCE_PROGRAM; + action, STATE_SET "show" 0.0; + target, PART_CHANNELINFO_LIST_NEXT; + target, PART_CHANNELINFO_LIST_CURRENT; + target, PART_CHANNELINFO_LIST_PREV; + sequence { + action, STATE_SET "up" 0.0; + transition, CUBIC_BEZIER 0.667 TRANSITION_EASE_IN_OUT; + target, PART_CHANNELINFO_LIST_NEXT; + target, PART_CHANNELINFO_LIST_CURRENT; + target, PART_CHANNELINFO_LIST_PREV; + after, "anim_end"; + } + } + program { + signal, SIGNAL_ANIM_MOVE_DOWN; + source, SOURCE_PROGRAM; + action, STATE_SET "show" 0.0; + target, PART_CHANNELINFO_LIST_NEXT; + target, PART_CHANNELINFO_LIST_CURRENT; + target, PART_CHANNELINFO_LIST_PREV; + sequence { + action, STATE_SET "down" 0.0; + transition, CUBIC_BEZIER 0.667 TRANSITION_EASE_IN_OUT; + target, PART_CHANNELINFO_LIST_NEXT; + target, PART_CHANNELINFO_LIST_CURRENT; + target, PART_CHANNELINFO_LIST_PREV; + after, "anim_end"; + } + } + program { + name, "anim_end"; + action, SIGNAL_EMIT SIGNAL_ANIM_FINISHED SOURCE_ELM; + } } } @@ -863,7 +954,6 @@ group { state, "default" 0.0; min, 536 70; align, 0.0 0.0; - fixed, 1 1; visible, 0; } } diff --git a/include/define.h b/include/define.h index 0012083..40d9be3 100644 --- a/include/define.h +++ b/include/define.h @@ -50,6 +50,9 @@ #define SIGNAL_HIDE "hide" #define SIGNAL_HIDE_FINISHED "elm,action,hide,finished" #define SIGNAL_TIMEOUT "timeout" +#define SIGNAL_ANIM_MOVE_UP "anim,move_up" +#define SIGNAL_ANIM_MOVE_DOWN "anim,move_down" +#define SIGNAL_ANIM_FINISHED "anim,finished" #define FONT_REGULAR "BreezeSans" #define FONT_LIGHT "BreezeSans:style=Light" diff --git a/src/layout_channelinfo_list.c b/src/layout_channelinfo_list.c index d64743c..8f5e7c6 100644 --- a/src/layout_channelinfo_list.c +++ b/src/layout_channelinfo_list.c @@ -25,6 +25,10 @@ #include "tv.h" #include "view.h" +#define TUNE_WAIT_TIME 0.1 +#define CHANNEL_PADDING_X 0 +#define CHANNEL_PADDING_Y 5 + static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev); @@ -38,6 +42,7 @@ struct _priv { Evas_Object *prev_channel; Evas_Object *current_channel; Evas_Object *next_channel; + Ecore_Timer *tune_timer; const struct tv_channel_info *channel_info; layoutmgr *lmgr; @@ -91,83 +96,142 @@ static int _set_next_channel(struct _priv *priv, int order) return 0; } -static void _update_channel_info(struct _priv *priv) +static bool _get_next_channel( + const struct tv_channel_info *current, + const struct tv_channel_info **prev, + const struct tv_channel_info **next) { - const struct tv_channel_info *prev, *current, *next, *channel; + const struct tv_channel_info *channel; Eina_List *channel_list, *l; - if (priv->channel_info) - current = priv->channel_info; - else { - current = tv_channel_get_info(); - if (!current) { - _ERR("failed to get channel info"); + if (!current) { + _ERR("failed to get current channel"); - return; - } + return false; } - util_draw_channel_info(priv->current_channel, current); - channel_list = tv_channel_get_list(); if (!channel_list) { _ERR("failed to get channel list"); - return; + + return false; } - prev = NULL; - next = NULL; + *prev = NULL; + *next = NULL; EINA_LIST_FOREACH(channel_list, l, channel) { if (channel->service_id == current->service_id) { - prev = eina_list_data_get(eina_list_prev(l)); - next = eina_list_data_get(eina_list_next(l)); + *prev = eina_list_data_get(eina_list_prev(l)); + *next = eina_list_data_get(eina_list_next(l)); break; } } - if (!prev) { - prev = eina_list_data_get(eina_list_last(channel_list)); - if (prev == current) - prev = NULL; + if (!*prev) + *prev = eina_list_data_get(eina_list_last(channel_list)); + + if (!*next) + *next = eina_list_data_get(channel_list); + + *prev = tv_channel_clone_info(*prev); + *next = tv_channel_clone_info(*next); + + tv_channel_del_list(channel_list); + + return true; +} + +static void _draw_channel_info(Evas_Object *box, + const struct tv_channel_info *current, char *grp) +{ + const struct tv_channel_info *prev, *next; + Evas_Object *layout; + + if (!current) { + _ERR("failed to get current channel"); + + return; + } + + if (!_get_next_channel(current, &prev, &next) || + !prev || !next) { + _ERR("failed to get next channel"); + + return; } - if (!next) { - next = eina_list_data_get(channel_list); - if (next == current) - next = NULL; + elm_box_clear(box); + + layout = util_add_layout(box, grp); + util_draw_channel_info(layout, next); + elm_box_pack_end(box, layout); + + layout = util_add_layout(box, grp); + util_draw_channel_info(layout, current); + elm_box_pack_end(box, layout); + + layout = util_add_layout(box, grp); + util_draw_channel_info(layout, prev); + elm_box_pack_end(box, layout); + + tv_channel_del_info(prev); + tv_channel_del_info(next); +} + +static void _update_channel_info(struct _priv *priv) +{ + const struct tv_channel_info *prev, *current, *next; + + if (priv->channel_info) + current = priv->channel_info; + else { + current = tv_channel_get_info(); + if (!current) { + _ERR("failed to get channel info"); + + return; + } } + if (!_get_next_channel(current, &prev, &next)) { + _ERR("failed to get next channel"); + + return; + } + + _draw_channel_info(priv->prev_channel, prev, GRP_CHANNELINFO_SIMPLE); + _draw_channel_info(priv->current_channel, current, GRP_CHANNELINFO); + _draw_channel_info(priv->next_channel, next, GRP_CHANNELINFO_SIMPLE); + if (prev) - util_draw_channel_info(priv->prev_channel, prev); + tv_channel_del_info(prev); if (next) - util_draw_channel_info(priv->next_channel, next); - - tv_channel_del_list(channel_list); + tv_channel_del_info(next); } static bool _draw_channel_layout(struct _priv *priv) { - priv->next_channel = util_add_layout(priv->base, - GRP_CHANNELINFO_SIMPLE); + priv->next_channel = util_add_box(priv->base, EINA_FALSE); if (!priv->next_channel) return false; - + elm_box_padding_set(priv->next_channel, + CHANNEL_PADDING_X, CHANNEL_PADDING_Y); elm_object_part_content_set(priv->base, PART_CHANNELINFO_LIST_NEXT, priv->next_channel); - priv->current_channel = util_add_layout(priv->base, GRP_CHANNELINFO); + priv->current_channel = util_add_box(priv->base, EINA_FALSE); if (!priv->current_channel) return false; - elm_object_part_content_set(priv->base, PART_CHANNELINFO_LIST_CURRENT, priv->current_channel); - priv->prev_channel = util_add_layout(priv->base, - GRP_CHANNELINFO_SIMPLE); + + priv->prev_channel = util_add_box(priv->base, EINA_FALSE); if (!priv->prev_channel) return false; - + elm_box_padding_set(priv->prev_channel, + CHANNEL_PADDING_X, CHANNEL_PADDING_Y); elm_object_part_content_set(priv->base, PART_CHANNELINFO_LIST_PREV, priv->prev_channel); @@ -197,6 +261,40 @@ static void _hide_finished_cb(void *data, Evas_Object *obj, evas_object_hide(priv->base); } +Eina_Bool _tune_timer(void *data) +{ + struct _priv *priv; + + if (!data) + return ECORE_CALLBACK_CANCEL; + + priv = data; + + tv_channel_tune_with_service_id( + priv->channel_info->service_id); + + priv->tune_timer = NULL; + + return ECORE_CALLBACK_CANCEL; +} + +static void _anim_finished_cb(void *data, Evas_Object *obj, + const char *emission, const char *source) +{ + struct _priv *priv; + + if (!data) + return; + + priv = data; + + if (priv->tune_timer) + ecore_timer_reset(priv->tune_timer); + else + priv->tune_timer = ecore_timer_add(TUNE_WAIT_TIME, + _tune_timer, priv); +} + static bool _create(layoutmgr *lmgr, void *data) { struct _priv *priv; @@ -240,6 +338,8 @@ static bool _create(layoutmgr *lmgr, void *data) inputmgr_add_callback(priv->base, 0, &key_handler, priv); elm_layout_signal_callback_add(priv->base, SIGNAL_HIDE_FINISHED, SOURCE_ELM, _hide_finished_cb, priv); + elm_layout_signal_callback_add(priv->base, SIGNAL_ANIM_FINISHED, + SOURCE_ELM, _anim_finished_cb, priv); return true; } @@ -256,9 +356,14 @@ static void _destroy(void *layout_data) if (priv->channel_info) tv_channel_del_info(priv->channel_info); + if (priv->tune_timer) + ecore_timer_del(priv->tune_timer); + inputmgr_remove_callback(priv->base, &key_handler); elm_layout_signal_callback_del(priv->base, SIGNAL_HIDE_FINISHED, SOURCE_ELM, _hide_finished_cb); + elm_layout_signal_callback_del(priv->base, SIGNAL_ANIM_FINISHED, + SOURCE_ELM, _anim_finished_cb); evas_object_del(priv->base); free(priv); @@ -316,39 +421,23 @@ static void _update(void *layout_data, int type, void *data) } if (!strcmp(ev->keyname, KEY_CHANNELUP)) { + _update_channel_info(priv); + + elm_object_signal_emit(priv->base, + SIGNAL_ANIM_MOVE_UP, SOURCE_PROGRAM); + r = _set_next_channel(priv, CHANNEL_NEXT); if (r < 0) _ERR("failed to set next channel"); - else - _update_channel_info(priv); } else if (!strcmp(ev->keyname, KEY_CHANNELDOWN)) { - r = _set_next_channel(priv, CHANNEL_PREV); - if (r < 0) - _ERR("failed to set prev channel"); - else - _update_channel_info(priv); - } - } else if (type == UPDATE_TYPE_INPUT_KEY_UP) { - Evas_Event_Key_Up *ev = data; - - if (!ev) { - _ERR("failed to get ev"); - return; - } + _update_channel_info(priv); - if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELDOWN)) { - if (!priv->channel_info) { - _ERR("failed to get channel info"); - return; - } + elm_object_signal_emit(priv->base, + SIGNAL_ANIM_MOVE_DOWN, SOURCE_PROGRAM); - r = tv_channel_tune_with_service_id( - priv->channel_info->service_id); + r = _set_next_channel(priv, CHANNEL_PREV); if (r < 0) - _ERR("failed to tune next channel"); - - _update_channel_info(priv); + _ERR("failed to set prev channel"); } } } -- 2.7.4 From 9507fb20fb50c129a4c632f3b18203dc86e5fc8b Mon Sep 17 00:00:00 2001 From: "jinwoo.shin" Date: Fri, 25 Sep 2015 19:22:08 +0900 Subject: [PATCH 16/16] Add channel prev key event Change-Id: I3629b9102bed34d4f8614a5262715ce87d8e9ed5 Signed-off-by: jinwoo.shin --- include/tv.h | 3 +- src/main.c | 10 ++- src/tv.c | 161 ++++++++++++++++++++++--------------------------- src/view_channelinfo.c | 31 +++------- 4 files changed, 91 insertions(+), 114 deletions(-) diff --git a/include/tv.h b/include/tv.h index 129b18b..1794033 100644 --- a/include/tv.h +++ b/include/tv.h @@ -74,11 +74,10 @@ Eina_List *tv_channel_search_by_number(long major, long minor); void tv_channel_del_list(Eina_List *channel_list); int tv_get_current_service_id(int *service_id); int tv_channel_tune(void); +int tv_channel_tune_prev_channel(void); int tv_channel_direct_tune(long major, long minor); int tv_channel_tune_with_service_id(int service_id); int tv_channel_tune_locked_channel(int service_id, char *password); -int tv_channel_next(void); -int tv_channel_prev(void); int tv_channel_set_favorite(int service_id, Eina_Bool flag); int tv_channel_add_channel(int service_id); int tv_channel_del_channel(int service_id); diff --git a/src/main.c b/src/main.c index 6bc6797..160a63d 100644 --- a/src/main.c +++ b/src/main.c @@ -45,6 +45,7 @@ struct _appdata { int is_signal; int is_channel; + int is_tuned; }; struct key_map { @@ -58,7 +59,8 @@ static struct key_map g_kmap[] = { { KEY_ENTER, KEY_CHANNELUP, - KEY_CHANNELDOWN + KEY_CHANNELDOWN, + KEY_PREVIOUS, } }, { @@ -176,6 +178,7 @@ static void _tv_signal_cb(void *data, int is_signal) ad = data; ad->is_signal = is_signal; + ad->is_tuned = true; if (is_signal) { viewmgr_hide_view(VIEW_ERROR); @@ -243,6 +246,8 @@ static void _resume(void *data) ui_app_exit(); return; + } else if (r > 0) { + ad->is_tuned = false; } /* Try to tune with service id if supplied from app control */ @@ -256,6 +261,9 @@ static void _resume(void *data) } } + if (ad->is_tuned) + return; + r = tv_channel_tune(); if (r < 0) { ad->is_channel = false; diff --git a/src/tv.c b/src/tv.c index d764ae5..46b0321 100644 --- a/src/tv.c +++ b/src/tv.c @@ -32,6 +32,11 @@ #define DEFAULT_SERVICE 1 +struct _channel_history { + int service_id[2]; + unsigned int idx; +}; + /** * The Storage structure to used by tv related functions and events. */ @@ -43,6 +48,8 @@ struct _tv_info { /**< Stores service id if tune to locked channel was succeeded. */ int viewing_locked_channel; + /**< Stores previous service id. */ + struct _channel_history history; /**< The function pointer to pass tv signal event */ void (*signal_cb)(void *data, int is_signal); @@ -651,14 +658,26 @@ void tv_channel_del_list(Eina_List *channel_list) free(data); } -void _tv_channel_add_history(int service_id) +static void _tv_channel_add_history(int service_id) { char buf[128]; + g_tv_info.history.service_id[g_tv_info.history.idx++ % 2] + = service_id; + snprintf(buf, sizeof(buf), "%d", service_id); app_contents_recent_add(CONTENTS_CHANNEL, buf); } +static int _tv_channel_get_history(void) +{ + int service_id; + + service_id = g_tv_info.history.service_id[g_tv_info.history.idx % 2]; + + return service_id; +} + /** * Tunes to specific channel with service id. * @@ -714,6 +733,42 @@ int tv_channel_tune(void) return -1; } + _tv_channel_add_history(service_id); + + g_tv_info.viewing_locked_channel = -1; + + return 0; +} + +/** + * Tunes to previously viewed channel. + * + * @return If the operation was sucessful 0 is returned; otherwise negative value is returned + */ +int tv_channel_tune_prev_channel(void) +{ + int service_id; + int r; + + if (!g_tv_info.live_svc) { + _ERR("failed to get live service"); + return -1; + } + + service_id = _tv_channel_get_history(); + if (service_id < 1) { + _ERR("no previous channel"); + return -1; + } + + r = tv_service_live_tune(g_tv_info.live_svc, service_id); + if (r != TVS_ERROR_OK) { + _ERR("failed to set service"); + return -1; + } + + _tv_channel_add_history(service_id); + g_tv_info.viewing_locked_channel = -1; return 0; @@ -732,6 +787,11 @@ int tv_channel_direct_tune(long major, long minor) TvServiceChannel *tvs_data; int r; + if (!g_tv_info.live_svc) { + _ERR("failed to get live service"); + return -1; + } + if (major > 0 && major < MAJOR_MAX) { filter_node = _tv_channel_get_filter( TV_SERVICE_CHANNEL_DATA_MAJOR_NUMBER, @@ -811,92 +871,6 @@ int tv_channel_tune_locked_channel(int service_id, char *password) } /** - * Tunes to next channel. - * - * Note that deleted channels and service channels will skipped. - * - * @return If the operation was sucessful 0 is returned; otherwise negative value is returned - */ -int tv_channel_next(void) -{ - TvServiceAntenna antenna_type; - int service_id, r; - - if (!g_tv_info.live_svc) { - _ERR("failed to get live service"); - return -1; - } - - r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type); - if (r < 0) { - _ERR("failed to get antenna type"); - return -1; - } - - r = tv_service_live_tune_up(g_tv_info.live_svc, - TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type); - if (r < 0) { - _ERR("failed to tune up"); - return -1; - } - - g_tv_info.viewing_locked_channel = -1; - - r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id); - if (r < 0) { - _ERR("failed to get service id"); - return -1; - } - - _tv_channel_add_history(service_id); - - return 0; -} - -/** - * Tunes to previous channel. - * - * Note that deleted channels and service channels will skipped. - * - * @return If the operation was sucessful 0 is returned; otherwise negative value is returned - */ -int tv_channel_prev(void) -{ - TvServiceAntenna antenna_type; - int service_id, r; - - if (!g_tv_info.live_svc) { - _ERR("failed to get live service"); - return -1; - } - - r = tv_service_live_get_antenna_type(g_tv_info.live_svc, &antenna_type); - if (r < 0) { - _ERR("failed to get antenna type"); - return -1; - } - - r = tv_service_live_tune_down(g_tv_info.live_svc, - TV_SERVICE_CHANNEL_MODE_DIGITAL_ANALOG, antenna_type); - if (r < 0) { - _ERR("failed to tune down"); - return -1; - } - - g_tv_info.viewing_locked_channel = -1; - - r = tv_service_live_get_service_id(g_tv_info.live_svc, &service_id); - if (r < 0) { - _ERR("failed to get service id"); - return -1; - } - - _tv_channel_add_history(service_id); - - return 0; -} - -/** * Sets the channel's favorite status. * * @param service_id The channel id @@ -1115,6 +1089,8 @@ int tv_create(void) goto err; } + memset(&g_tv_info.history, 0, sizeof(g_tv_info.history)); + return 0; err: tv_destroy(); @@ -1160,9 +1136,16 @@ int tv_resume(void) if (r != TVS_ERROR_OK) { _ERR("failed to create live service"); goto err; - } else { - return 1; } + + r = tv_service_live_register_callback(g_tv_info.live_svc, + _tv_service_event_cb, NULL); + if (r != TVS_ERROR_OK) { + _ERR("failed to register live callback"); + goto err; + } + + return 1; } r = tv_service_live_tune_resume(g_tv_info.live_svc); diff --git a/src/view_channelinfo.c b/src/view_channelinfo.c index 610e5a3..08191e3 100644 --- a/src/view_channelinfo.c +++ b/src/view_channelinfo.c @@ -49,11 +49,10 @@ static void _hide_current_layout(struct _priv *priv) static void _set_current_layout(struct _priv *priv, const char *layout_id) { - if (priv->current_layout && layout_id && - !strcmp(priv->current_layout, layout_id)) + if (!layout_id) return; - if (priv->current_layout) + if (priv->current_layout && strcmp(priv->current_layout, layout_id)) layoutmgr_hide_layout(priv->lmgr, priv->current_layout); layoutmgr_show_layout(priv->lmgr, layout_id); @@ -170,6 +169,7 @@ static void _destroy(void *view_data) static void _update(void *view_data, int type, void *data) { struct _priv *priv; + int r; if (!view_data) { _ERR("failed to get view data"); @@ -211,28 +211,15 @@ static void _update(void *view_data, int type, void *data) _set_current_layout(priv, LAYOUT_CHANNELINFO_LIST); layoutmgr_update_layout(priv->lmgr, LAYOUT_CHANNELINFO_LIST, type, ev); - } - - viewmgr_show_view(VIEW_CHANNELINFO); - } else if (type == UPDATE_TYPE_INPUT_KEY_UP) { - Evas_Event_Key_Up *ev = data; + } else if (!strcmp(ev->keyname, KEY_PREVIOUS)) { + r = tv_channel_tune_prev_channel(); + if (r < 0) + _ERR("failed to tune prev channel"); - if (!ev) { - _ERR("failed to get ev"); - return; + _set_current_layout(priv, LAYOUT_CHANNELINFO); } - if (!strcmp(ev->keyname, KEY_CHANNELUP) || - !strcmp(ev->keyname, KEY_CHANNELDOWN)) { - if (priv->current_layout && - !strcmp(priv->current_layout, - LAYOUT_CHANNELINFO_SEARCH)) - return; - - _set_current_layout(priv, LAYOUT_CHANNELINFO_LIST); - layoutmgr_update_layout(priv->lmgr, - LAYOUT_CHANNELINFO_LIST, type, ev); - } + viewmgr_show_view(VIEW_CHANNELINFO); } } -- 2.7.4