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
This commit is contained in:
Jyotiprakash Sahoo 2014-12-16 16:56:34 +09:00 committed by Carsten Haitzler (Rasterman)
parent be15a0dc33
commit 17419ec81c
5 changed files with 326 additions and 6 deletions

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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"

View File

@ -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;