raster pushed a commit to branch master. http://git.enlightenment.org/core/elementary.git/commit/?id=f99be3a1d6bdc63153598b592b5437c33da44bf0
commit f99be3a1d6bdc63153598b592b5437c33da44bf0 Author: Jyotiprakash Sahoo <[email protected]> Date: Tue Dec 16 16:56:34 2014 +0900 genlist: added reorder feature on key events Summary: This feature allows user to reorder items using up/down keys. Test Plan: elementary_test -to "Genlist Reorder Mode" Reviewers: singh.amitesh, raster, seoz, SanghyeonLee Differential Revision: https://phab.enlightenment.org/D1262 Conflicts: src/bin/test_genlist.c src/lib/elm_genlist_legacy.h --- src/bin/test_genlist.c | 141 ++++++++++++++++++++++++++++++++++++++++- src/lib/elm_genlist.c | 145 ++++++++++++++++++++++++++++++++++++++++++- src/lib/elm_genlist.h | 7 ++- src/lib/elm_genlist_legacy.h | 30 ++++++++- src/lib/elm_widget_genlist.h | 9 +++ 5 files changed, 326 insertions(+), 6 deletions(-) diff --git a/src/bin/test_genlist.c b/src/bin/test_genlist.c index 448e417..6c9ddb8 100644 --- a/src/bin/test_genlist.c +++ b/src/bin/test_genlist.c @@ -5,6 +5,8 @@ #endif #include <Elementary.h> +static int tween_mode_val; + Evas_Object * _elm_min_set(Evas_Object *obj, Evas_Object *parent, Evas_Coord w, Evas_Coord h); @@ -2087,6 +2089,44 @@ _reorder_tg_changed_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSE elm_genlist_reorder_mode_set(data, elm_check_state_get(obj)); } +static void +_focus_highlight_ck_changed_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + elm_win_focus_highlight_enabled_set(data, elm_check_state_get(obj)); +} + +static void +_tween_mode_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + switch (tween_mode_val) + { + case 1: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_LINEAR); + break; + case 2: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_ACCELERATE); + break; + case 3: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_DECELERATE); + break; + case 4: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_SINUSOIDAL); + break; + case 5: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_DIVISOR_INTERP); + break; + case 6: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_BOUNCE); + break; + case 7: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_SPRING); + break; + default: + elm_genlist_reorder_mode_start(data, ECORE_POS_MAP_LINEAR); + break; + } +} + /** * gl_moved is called after an item was reordered. * This is only called when reorder mode is enabled. @@ -2144,11 +2184,12 @@ static void gl_moved_before(Evas_Object *data EINA_UNUSED, Evas_Object *obj EINA void test_genlist11(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { - Evas_Object *win, *fr, *lb, *bx, *tg, *gl; + Evas_Object *win, *fr, *lb, *bx, *tg, *gl, *hbx, *ck, *grp, *rd; int i; api_data *api = calloc(1, sizeof(api_data)); win = elm_win_util_standard_add("genlist-reorder-mode", "Genlist Reorder Mode"); + elm_win_focus_highlight_enabled_set(win, EINA_TRUE); elm_win_autodel_set(win, EINA_TRUE); evas_object_event_callback_add(win, EVAS_CALLBACK_FREE, _cleanup_cb, api); @@ -2176,20 +2217,116 @@ test_genlist11(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event api->gl = gl; evas_object_show(gl); + hbx = elm_box_add(win); + elm_box_horizontal_set(hbx, EINA_TRUE); + evas_object_size_hint_weight_set(hbx, EVAS_HINT_EXPAND, 0); + elm_box_padding_set(hbx, 20, 0); + elm_box_pack_end(bx, hbx); + evas_object_show(hbx); + tg = elm_check_add(win); elm_object_style_set(tg, "toggle"); elm_object_text_set(tg, "Reorder Mode:"); elm_check_state_set(tg, elm_config_mirrored_get()); evas_object_smart_callback_add(tg, "changed", _reorder_tg_changed_cb, gl); - elm_box_pack_end(bx, tg); + elm_box_pack_end(hbx, tg); evas_object_show(tg); + ck = elm_check_add(win); + elm_object_text_set(ck, "Focus Highlight"); + elm_check_state_set(ck, elm_win_focus_highlight_enabled_get(win)); + evas_object_smart_callback_add(ck, "changed", _focus_highlight_ck_changed_cb, win); + elm_box_pack_end(hbx, ck); + evas_object_show(ck); + + lb = elm_label_add(win); + elm_object_text_set(lb, "Select reorder tween mode:"); + elm_box_pack_end(bx, lb); + evas_object_show(lb); + + hbx = elm_box_add(win); + elm_box_horizontal_set(hbx, EINA_TRUE); + evas_object_size_hint_weight_set(hbx, EVAS_HINT_EXPAND, 0); + elm_box_pack_end(bx, hbx); + evas_object_show(hbx); + + grp = rd = elm_radio_add(win); + elm_object_text_set(rd, "Linear"); + elm_radio_state_value_set(rd, 1); + elm_radio_value_pointer_set(rd, &tween_mode_val); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Accelerate"); + elm_radio_state_value_set(rd, 2); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Decelerate"); + elm_radio_state_value_set(rd, 3); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Sinusoidal"); + elm_radio_state_value_set(rd, 4); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + hbx = elm_box_add(win); + elm_box_horizontal_set(hbx, EINA_TRUE); + evas_object_size_hint_weight_set(hbx, EVAS_HINT_EXPAND, 0); + elm_box_pack_end(bx, hbx); + evas_object_show(hbx); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Divisor Interpolation"); + elm_radio_state_value_set(rd, 5); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Bounce"); + elm_radio_state_value_set(rd, 6); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + rd = elm_radio_add(win); + elm_object_text_set(rd, "Spring"); + elm_radio_state_value_set(rd, 7); + elm_radio_value_pointer_set(rd, &tween_mode_val); + elm_radio_group_add(rd, grp); + evas_object_smart_callback_add(rd, "changed", _tween_mode_changed_cb, gl); + elm_box_pack_end(hbx, rd); + evas_object_show(rd); + + elm_radio_value_set(grp, 1); + api->itc1 = elm_genlist_item_class_new(); api->itc1->item_style = "default"; api->itc1->func.text_get = gl_text_get; api->itc1->func.content_get = gl_content_get; api->itc1->func.state_get = gl_state_get; api->itc1->func.del = NULL; + evas_object_smart_callback_add(gl, "moved", (Evas_Smart_Cb)gl_moved, gl); evas_object_smart_callback_add(gl, "moved,after", (Evas_Smart_Cb)gl_moved_after, gl); evas_object_smart_callback_add(gl, "moved,before", (Evas_Smart_Cb)gl_moved_before, gl); diff --git a/src/lib/elm_genlist.c b/src/lib/elm_genlist.c index 1d858e8..8656e22 100644 --- a/src/lib/elm_genlist.c +++ b/src/lib/elm_genlist.c @@ -89,7 +89,9 @@ cmd(SIG_ITEM_FOCUSED, "item,focused", "") \ cmd(SIG_ITEM_UNFOCUSED, "item,unfocused", "") \ cmd(SIG_PRESSED, "pressed", "") \ - cmd(SIG_RELEASED, "released", "") + cmd(SIG_RELEASED, "released", "") \ + cmd(SIG_ITEM_REORDER_START, "item,reorder,anim,start", "") \ + cmd(SIG_ITEM_REORDER_STOP, "item,reorder,anim,stop", "") ELM_PRIV_GENLIST_SIGNALS(ELM_PRIV_STATIC_VARIABLE_DECLARE); @@ -109,7 +111,11 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = { static Eina_Bool _key_action_move(Evas_Object *obj, const char *params); static Eina_Bool _key_action_select(Evas_Object *obj, const char *params); static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params); - +static void _item_move_after(Elm_Gen_Item *it, Elm_Gen_Item *after); +static void _item_move_before(Elm_Gen_Item *it, Elm_Gen_Item *before); +EOLIAN static void _elm_genlist_reorder_mode_set(Eo *obj EINA_UNUSED, + Elm_Genlist_Data *sd, + Eina_Bool reorder_mode); static const Elm_Action key_actions[] = { {"move", _key_action_move}, @@ -2716,6 +2722,98 @@ _key_action_move_dir(Evas_Object *obj, Elm_Focus_Direction dir, Eina_Bool multi) return EINA_FALSE; } +static void +_anim_end(Elm_Genlist_Data *sd) +{ + if (sd->reorder.dir == ELM_FOCUS_UP) + _item_move_after(sd->reorder.it2, sd->reorder.it1); + else if (sd->reorder.dir == ELM_FOCUS_DOWN) + _item_move_after(sd->reorder.it1, sd->reorder.it2); + + ecore_job_del(sd->calc_job); + sd->calc_job = ecore_job_add(_calc_job, sd->obj); +} + +static Eina_Bool +_item_swap_cb(void *data, double pos) +{ + Elm_Genlist_Data *sd = data; + double frame = pos; + Evas_Coord xx1, yy1, xx2, yy2; + double dx, dy; + + switch (sd->reorder.tween_mode) + { + case ECORE_POS_MAP_LINEAR: + frame = ecore_animator_pos_map(frame, sd->reorder.tween_mode, 0, 0); + break; + case ECORE_POS_MAP_ACCELERATE: + case ECORE_POS_MAP_DECELERATE: + case ECORE_POS_MAP_SINUSOIDAL: + frame = ecore_animator_pos_map(frame, sd->reorder.tween_mode, 1.0, 0); + break; + case ECORE_POS_MAP_DIVISOR_INTERP: + case ECORE_POS_MAP_BOUNCE: + case ECORE_POS_MAP_SPRING: + frame = ecore_animator_pos_map(frame, sd->reorder.tween_mode, 1.0, 1.0); + break; + default: + // use ECORE_POS_MAP_LINEAR as default tween mode + frame = ecore_animator_pos_map(frame, sd->reorder.tween_mode, 0, 0); + break; + } + + dx = sd->reorder.x2 - sd->reorder.x1; + dy = sd->reorder.y2 - sd->reorder.y1; + + xx1 = sd->reorder.x1 + (dx * frame); + yy1 = sd->reorder.y1 + (dy * frame); + xx2 = sd->reorder.x2 - (dx * frame); + yy2 = sd->reorder.y2 - (dy * frame); + + evas_object_move(VIEW(sd->reorder.it2), xx2, yy2); + evas_object_move(VIEW(sd->reorder.it1), xx1, yy1); + + if (pos == 1.0) + { + elm_genlist_item_bring_in((Elm_Object_Item *)sd->reorder.it2, ELM_GENLIST_ITEM_SCROLLTO_IN); + _anim_end(sd); + evas_object_smart_callback_call(sd->obj, SIG_ITEM_REORDER_STOP, sd->reorder.it1); + sd->reorder.running = EINA_FALSE; + } + + _elm_widget_focus_highlight_start(sd->obj); + + return EINA_TRUE; +} + + +static void +_swap_items(Elm_Gen_Item *it1, Elm_Gen_Item *it2, Elm_Focus_Direction dir) +{ + ELM_GENLIST_DATA_GET_FROM_ITEM(it1, sd); + Evas_Coord xx1, yy1, xx2, yy2; + + if (!it1 || !it2) return; + + sd->reorder.running = EINA_TRUE; + sd->reorder.dir = dir; + sd->reorder.it1 = it1; + sd->reorder.it2 = it2; + + evas_object_geometry_get(VIEW(it1), &xx1, &yy1, NULL, NULL); + evas_object_geometry_get(VIEW(it2), &xx2, &yy2, NULL, NULL); + sd->reorder.x1 = xx1; + sd->reorder.y1 = yy1; + sd->reorder.x2 = xx2; + sd->reorder.y2 = yy2; + + evas_object_raise(VIEW(it1)); + evas_object_smart_callback_call(sd->obj, SIG_ITEM_REORDER_START, sd->reorder.it1); + //TODO: Add elm config for time + ecore_animator_timeline_add(0.3, _item_swap_cb, sd); +} + static Eina_Bool _key_action_move(Evas_Object *obj, const char *params) { @@ -2762,6 +2860,18 @@ _key_action_move(Evas_Object *obj, const char *params) } else if (!strcmp(dir, "up")) { + if (sd->reorder.running) return EINA_TRUE; + if (sd->reorder_mode) + { + Elm_Gen_Item *up = (Elm_Gen_Item *)elm_genlist_item_prev_get(sd->focused_item); + ELM_GENLIST_ITEM_DATA_GET(sd->focused_item, focused_it); + ELM_GENLIST_ITEM_DATA_GET(up, up2); + + _swap_items(focused_it, up2, ELM_FOCUS_UP); + + return EINA_TRUE; + } + if (_key_action_move_dir(obj, ELM_FOCUS_UP, EINA_FALSE)) return EINA_TRUE; else return EINA_FALSE; } @@ -2773,6 +2883,18 @@ _key_action_move(Evas_Object *obj, const char *params) } else if (!strcmp(dir, "down")) { + if (sd->reorder.running) return EINA_TRUE; + if (sd->reorder_mode) + { + Elm_Gen_Item *down = (Elm_Gen_Item *)elm_genlist_item_next_get(sd->focused_item); + ELM_GENLIST_ITEM_DATA_GET(sd->focused_item, focused_it); + ELM_GENLIST_ITEM_DATA_GET(down, down2); + + _swap_items(focused_it, down2, ELM_FOCUS_DOWN); + + return EINA_TRUE; + } + if (_key_action_move_dir(obj, ELM_FOCUS_DOWN, EINA_FALSE)) return EINA_TRUE; else return EINA_FALSE; } @@ -7342,6 +7464,25 @@ _elm_genlist_decorate_mode_set(Eo *obj, Elm_Genlist_Data *sd, Eina_Bool decorate sd->calc_job = ecore_job_add(_calc_job, sd->obj); } +EAPI void +elm_genlist_reorder_mode_start(Evas_Object *obj, Ecore_Pos_Map tween_mode) +{ + ELM_GENLIST_CHECK(obj); + ELM_GENLIST_DATA_GET(obj, sd); + + sd->reorder.tween_mode = tween_mode; + _elm_genlist_reorder_mode_set(obj, sd, EINA_TRUE); +} + +EAPI void +elm_genlist_reorder_mode_stop(Evas_Object *obj) +{ + ELM_GENLIST_CHECK(obj); + ELM_GENLIST_DATA_GET(obj, sd); + + _elm_genlist_reorder_mode_set(obj, sd, EINA_FALSE); +} + EOLIAN static void _elm_genlist_reorder_mode_set(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, Eina_Bool reorder_mode) { diff --git a/src/lib/elm_genlist.h b/src/lib/elm_genlist.h index c95d472..af6f06f 100644 --- a/src/lib/elm_genlist.h +++ b/src/lib/elm_genlist.h @@ -379,7 +379,12 @@ * - @c "unfocused" - When the genlist has lost focus. (since 1.8) * - @c "item,focused" - When the genlist item has recieved focus. (since 1.10) * - @c "item,unfocused" - When the genlist item has lost focus. (since 1.10) - * + * - @c "item,reorder,anim,start" - This is called when a genglist item's movement + has just started by keys in reorder mode. The %c event_info parameter + * is the item that is going to move. (since 1.13) + * - @c "item,reorder,anim,stop" - This is called when a genlist item's movement just + stopped in reorder mode. The %c event_info parameter is the item + that was moved. (since 1.13) * * Supported elm_object_item common APIs * @li @ref elm_object_item_part_content_get diff --git a/src/lib/elm_genlist_legacy.h b/src/lib/elm_genlist_legacy.h index 77866c0..f8345ed 100644 --- a/src/lib/elm_genlist_legacy.h +++ b/src/lib/elm_genlist_legacy.h @@ -31,5 +31,33 @@ EAPI Evas_Object *elm_genlist_add(Evas_Object *parent); EAPI Elm_Object_Item * elm_genlist_nth_item_get(const Evas_Object *obj, unsigned int nth); -#include "elm_genlist_item.eo.legacy.h" +/** + * Enable item reorder mode with keys for genlist widget + * + * @param obj The genlist object + * @param tween_mode Position mappings for animation + * @see _Ecore_Pos_Map + * + * @see elm_genlist_reorder_mode_stop() + * @since 1.13 + * + * @ingroup Genlist + */ +EAPI void +elm_genlist_reorder_mode_start(Evas_Object *obj, Ecore_Pos_Map tween_mode); + +/** + * Stop item reorder mode with keys for genlist widget + * + * @param obj The genlist object + * + * @see elm_genlist_reorder_mode_start() + * @since 1.13 + * + * @ingroup Genlist + */ +EAPI void +elm_genlist_reorder_mode_stop(Evas_Object *obj); + #include "elm_genlist.eo.legacy.h" +#include "elm_genlist_item.eo.legacy.h" diff --git a/src/lib/elm_widget_genlist.h b/src/lib/elm_widget_genlist.h index 623ae65..3cdeb0b 100644 --- a/src/lib/elm_widget_genlist.h +++ b/src/lib/elm_widget_genlist.h @@ -140,6 +140,15 @@ struct _Elm_Genlist_Data Elm_Genlist_Item_Move_Effect_Mode move_effect_mode; int reorder_fast; + struct + { + Elm_Gen_Item *it1, *it2; /**< The items which are getting swapped */ + Elm_Focus_Direction dir; /**< focus key direction */ + Ecore_Pos_Map tween_mode; /**< Position mappings for animation */ + Evas_Coord x1, y1, x2, y2; /**< Coordinates of it1 and it2 */ + Eina_Bool running : 1; /**< animation is happening */ + } reorder; + Eina_Bool focus_on_selection_enabled : 1; Eina_Bool tree_effect_enabled : 1; Eina_Bool auto_scroll_enabled : 1; --
