diff --git a/legacy/elementary/ChangeLog b/legacy/elementary/ChangeLog index 25491d3fda..5c93f4e0a3 100644 --- a/legacy/elementary/ChangeLog +++ b/legacy/elementary/ChangeLog @@ -26,3 +26,8 @@ * Font: actually it doesnt append the font to the hash when font_hash is created inside. Now it is fixed. + +2012-05-03 WooHyun Jung + + * Add feature about focus. Focus can be moved in all direction by + by elm_widget_focus_go function. diff --git a/legacy/elementary/NEWS b/legacy/elementary/NEWS index 30d6ace161..70754cfe63 100644 --- a/legacy/elementary/NEWS +++ b/legacy/elementary/NEWS @@ -5,6 +5,8 @@ Changes since Elementary 1.0.0: Additions: + * Focus can be moved in all directions by elm_widget_focus_go function. + Fixes: * Genlist : Fixed genlist expandable effect bug when we expand/contract items with many children very quickly. diff --git a/legacy/elementary/src/bin/test_focus.c b/legacy/elementary/src/bin/test_focus.c index af30f30983..607d4b10b2 100644 --- a/legacy/elementary/src/bin/test_focus.c +++ b/legacy/elementary/src/bin/test_focus.c @@ -80,7 +80,7 @@ test_focus(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info { Evas_Object *lb = elm_label_add(win); - elm_object_text_set(lb, "Use Tab or Shift+Tab"); + elm_object_text_set(lb, "Use Tab or Shift+Tab
or Arrow keys
"); evas_object_size_hint_weight_set(lb, 0.0, 0.0); evas_object_size_hint_align_set(lb, EVAS_HINT_FILL, EVAS_HINT_FILL); diff --git a/legacy/elementary/src/lib/elm_box.c b/legacy/elementary/src/lib/elm_box.c index bcf0b382ac..4e00ae5ad6 100644 --- a/legacy/elementary/src/lib/elm_box.c +++ b/legacy/elementary/src/lib/elm_box.c @@ -127,6 +127,31 @@ _elm_box_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_O return elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next); } +static Eina_Bool +_elm_box_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Widget_Data *wd = elm_widget_data_get(obj); + const Eina_List *items; + void *(*list_data_get) (const Eina_List *list); + + if ((!wd) || (!wd->box)) + return EINA_FALSE; + + if ((items = elm_widget_focus_custom_chain_get(obj))) + list_data_get = eina_list_data_get; + else + { + Evas_Object_Box_Data *bd = evas_object_smart_data_get(wd->box); + items = bd->children; + list_data_get = _elm_box_list_data_get; + + if (!items) return EINA_FALSE; + } + return elm_widget_focus_list_direction_get(obj, base, items, list_data_get, degree, + direction, weight); +} + static void _theme_hook(Evas_Object *obj) { @@ -360,6 +385,7 @@ elm_box_add(Evas_Object *parent) elm_widget_del_hook_set(obj, _del_hook); elm_widget_del_pre_hook_set(obj, _del_pre_hook); elm_widget_focus_next_hook_set(obj, _elm_box_focus_next_hook); + elm_widget_focus_direction_hook_set(obj, _elm_box_focus_direction_hook); elm_widget_can_focus_set(obj, EINA_FALSE); elm_widget_highlight_ignore_set(obj, EINA_TRUE); elm_widget_theme_hook_set(obj, _theme_hook); diff --git a/legacy/elementary/src/lib/elm_bubble.c b/legacy/elementary/src/lib/elm_bubble.c index 0f35578761..ee6eea6db6 100644 --- a/legacy/elementary/src/lib/elm_bubble.c +++ b/legacy/elementary/src/lib/elm_bubble.c @@ -213,6 +213,19 @@ _elm_bubble_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Eva return elm_widget_focus_next_get(cur, dir, next); } +static Eina_Bool +_elm_bubble_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Widget_Data *wd = elm_widget_data_get(obj); + + if ((!wd) || (!wd->content)) + return EINA_FALSE; + + /* Try Focus cycle in subitem */ + return elm_widget_focus_direction_get(wd->content, base, degree, direction, weight); +} + static void _sizing_eval(Evas_Object *obj) { @@ -322,6 +335,7 @@ elm_bubble_add(Evas_Object *parent) elm_widget_del_hook_set(obj, _del_hook); elm_widget_theme_hook_set(obj, _theme_hook); elm_widget_focus_next_hook_set(obj, _elm_bubble_focus_next_hook); + elm_widget_focus_direction_hook_set(obj, _elm_bubble_focus_direction_hook); elm_widget_can_focus_set(obj, EINA_FALSE); elm_widget_text_set_hook_set(obj, _elm_bubble_label_set); elm_widget_text_get_hook_set(obj, _elm_bubble_label_get); diff --git a/legacy/elementary/src/lib/elm_frame.c b/legacy/elementary/src/lib/elm_frame.c index 0d32c16b7c..48a2893a58 100644 --- a/legacy/elementary/src/lib/elm_frame.c +++ b/legacy/elementary/src/lib/elm_frame.c @@ -77,6 +77,19 @@ _elm_frame_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas return elm_widget_focus_next_get(wd->content, dir, next); } +static Eina_Bool +_elm_frame_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Widget_Data *wd = elm_widget_data_get(obj); + + if ((!wd) || (!wd->content)) + return EINA_FALSE; + + /* Try Focus cycle in subitem */ + return elm_widget_focus_direction_get(wd->content, base, degree, direction, weight); +} + static void _sizing_eval(Evas_Object *obj) { @@ -240,6 +253,7 @@ elm_frame_add(Evas_Object *parent) elm_widget_del_hook_set(obj, _del_hook); elm_widget_theme_hook_set(obj, _theme_hook); elm_widget_focus_next_hook_set(obj, _elm_frame_focus_next_hook); + elm_widget_focus_direction_hook_set(obj, _elm_frame_focus_direction_hook); elm_widget_can_focus_set(obj, EINA_FALSE); elm_widget_text_set_hook_set(obj, _elm_frame_label_set); elm_widget_text_get_hook_set(obj, _elm_frame_label_get); diff --git a/legacy/elementary/src/lib/elm_layout.c b/legacy/elementary/src/lib/elm_layout.c index 6f144849b2..a5de5a675f 100644 --- a/legacy/elementary/src/lib/elm_layout.c +++ b/legacy/elementary/src/lib/elm_layout.c @@ -180,6 +180,32 @@ _elm_layout_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Eva next); } +static Eina_Bool +_elm_layout_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Widget_Data *wd = elm_widget_data_get(obj); + const Eina_List *items; + void *(*list_data_get) (const Eina_List *list); + + if ((!wd) || (!wd->subs)) + return EINA_FALSE; + + /* Focus chain (This block is diferent of elm_win cycle)*/ + if ((items = elm_widget_focus_custom_chain_get(obj))) + list_data_get = eina_list_data_get; + else + { + items = wd->subs; + list_data_get = _elm_layout_list_data_get; + + if (!items) return EINA_FALSE; + } + + return elm_widget_focus_list_direction_get(obj, base, items, list_data_get, degree, + direction, weight); +} + static void _sizing_eval(Widget_Data *wd) { @@ -458,6 +484,7 @@ elm_layout_add(Evas_Object *parent) elm_widget_changed_hook_set(obj, _changed_hook); elm_widget_can_focus_set(obj, EINA_FALSE); elm_widget_focus_next_hook_set(obj, _elm_layout_focus_next_hook); + elm_widget_focus_direction_hook_set(obj, _elm_layout_focus_direction_hook); elm_widget_signal_emit_hook_set(obj, _signal_emit_hook); elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook); elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook); diff --git a/legacy/elementary/src/lib/elm_scroller.c b/legacy/elementary/src/lib/elm_scroller.c index 49959b277b..c253ac7f7d 100644 --- a/legacy/elementary/src/lib/elm_scroller.c +++ b/legacy/elementary/src/lib/elm_scroller.c @@ -68,31 +68,134 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty Evas_Coord v_h = 0; Evas_Coord page_x = 0; Evas_Coord page_y = 0; + Evas_Coord c_x = 0; + Evas_Coord c_y = 0; elm_smart_scroller_child_pos_get(wd->scr, &x, &y); elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y); elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y); elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h); - elm_scroller_child_size_get(obj, &max_x, &max_y); + evas_object_geometry_get(wd->content, &c_x, &c_y, &max_x, &max_y); + if (((!strcmp(ev->keyname, "Left")) || + (!strcmp(ev->keyname, "KP_Left")) || + (!strcmp(ev->keyname, "Right")) || + (!strcmp(ev->keyname, "KP_Right")) || + (!strcmp(ev->keyname, "Up")) || + (!strcmp(ev->keyname, "KP_Up")) || + (!strcmp(ev->keyname, "Down")) || + (!strcmp(ev->keyname, "KP_Down"))) && (!ev->string)) + { + Evas_Object *current_focus = NULL; + Evas_Object *new_focus = NULL; + Eina_List *can_focus_list = NULL; + Evas_Coord f_x = 0; + Evas_Coord f_y = 0; + Evas_Coord f_w = 0; + Evas_Coord f_h = 0; + + current_focus = elm_widget_focused_object_get(obj); + evas_object_geometry_get(current_focus, &f_x, &f_y, &f_w, &f_h); + can_focus_list = elm_widget_can_focus_child_list_get(obj); + if ((current_focus == obj) || + (!ELM_RECTS_INTERSECT(x, y, v_w, v_h, + (f_x - c_x), (f_y - c_y), f_w, f_h))) + { + Evas_Object *cur; + Eina_List *l; + double weight = 0.0; + + EINA_LIST_FOREACH(can_focus_list, l, cur) + { + double cur_weight = 0.0; + evas_object_geometry_get(cur, &f_x, &f_y, &f_w, &f_h); + if (ELM_RECTS_INTERSECT(x, y, v_w, v_h, + (f_x - c_x), (f_y - c_y), f_w, f_h)) + { + if ((f_x - c_x) > x) + cur_weight += ((f_x - c_x) - x) * ((f_x - c_x) - x); + if ((f_y - c_y) > y) + cur_weight += ((f_y - c_y) - y) * ((f_y - c_y) - y); + if (cur_weight == 0.0) + { + elm_widget_focus_steal(cur); + return EINA_TRUE; + } + cur_weight = 1.0 / cur_weight; + if (cur_weight > weight) + { + new_focus = cur; + weight = cur_weight; + } + } + } + if (new_focus) + { + elm_widget_focus_steal(new_focus); + return EINA_TRUE; + } + } + else + { + Evas_Object *tmp = NULL; + double degree = 0.0, weight = 0.0; + void *(*list_data_get) (const Eina_List *list); + list_data_get = eina_list_data_get; + + if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left"))) + degree = 270.0; + else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right"))) + degree = 90.0; + else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up"))) + degree = 0.0; + else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down"))) + degree = 180.0; + + if (elm_widget_focus_list_direction_get(obj, current_focus, can_focus_list, list_data_get, degree, &tmp, &weight)) + new_focus = tmp; + + if (new_focus) + { + Evas_Coord l_x = 0; + Evas_Coord l_y = 0; + Evas_Coord l_w = 0; + Evas_Coord l_h = 0; + + evas_object_geometry_get(new_focus, &f_x, &f_y, &f_w, &f_h); + l_x = f_x - c_x - step_x; + l_y = f_y - c_y - step_y; + l_w = f_w + (step_x * 2); + l_h = f_h + (step_y * 2); + if (ELM_RECTS_INTERSECT(x, y, v_w, v_h, l_x, l_y, l_w, l_h)) + { + elm_widget_focus_steal(new_focus); + return EINA_TRUE; + } + } + } + } if ((!strcmp(ev->keyname, "Left")) || ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string))) { + if (x <= 0) return EINA_FALSE; x -= step_x; } else if ((!strcmp(ev->keyname, "Right")) || ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string))) { + if (x >= (max_x - v_w)) return EINA_FALSE; x += step_x; } else if ((!strcmp(ev->keyname, "Up")) || ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string))) { + if (y == 0) return EINA_FALSE; y -= step_y; } else if ((!strcmp(ev->keyname, "Down")) || ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string))) { + if (y >= (max_y - v_h)) return EINA_FALSE; y += step_y; } else if ((!strcmp(ev->keyname, "Home")) || diff --git a/legacy/elementary/src/lib/elm_table.c b/legacy/elementary/src/lib/elm_table.c index 532ccf4379..863f34acba 100644 --- a/legacy/elementary/src/lib/elm_table.c +++ b/legacy/elementary/src/lib/elm_table.c @@ -69,6 +69,43 @@ _elm_table_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas return ret; } +static Eina_Bool +_elm_table_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Widget_Data *wd = elm_widget_data_get(obj); + const Eina_List *items; + void *(*list_data_get) (const Eina_List *list); + Eina_List *(*list_free) (Eina_List *list); + + if ((!wd) || (!wd->tbl)) + return EINA_FALSE; + + /* Focus chain */ + /* TODO: Change this to use other chain */ + if ((items = elm_widget_focus_custom_chain_get(obj))) + { + list_data_get = eina_list_data_get; + list_free = NULL; + } + else + { + items = evas_object_table_children_get(wd->tbl); + list_data_get = eina_list_data_get; + list_free = eina_list_free; + + if (!items) return EINA_FALSE; + } + + Eina_Bool ret = elm_widget_focus_list_direction_get(obj, base, items, list_data_get, degree, + direction, weight); + + if (list_free) + list_free((Eina_List *)items); + + return ret; +} + static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl) { @@ -133,6 +170,7 @@ elm_table_add(Evas_Object *parent) elm_widget_del_hook_set(obj, _del_hook); elm_widget_del_pre_hook_set(obj, _del_pre_hook); elm_widget_focus_next_hook_set(obj, _elm_table_focus_next_hook); + elm_widget_focus_direction_hook_set(obj, _elm_table_focus_direction_hook); elm_widget_can_focus_set(obj, EINA_FALSE); elm_widget_highlight_ignore_set(obj, EINA_FALSE); elm_widget_theme_hook_set(obj, _theme_hook); diff --git a/legacy/elementary/src/lib/elm_widget.c b/legacy/elementary/src/lib/elm_widget.c index 4b62b63b8f..8941e7f95a 100644 --- a/legacy/elementary/src/lib/elm_widget.c +++ b/legacy/elementary/src/lib/elm_widget.c @@ -60,6 +60,11 @@ struct _Smart_Data Eina_Bool (*focus_next_func)(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next); + Eina_Bool (*focus_direction_func)(const Evas_Object *obj, + const Evas_Object *base, + double degree, + Evas_Object **direction, + double *weight); void (*on_focus_func)(void *data, Evas_Object *obj); void *on_focus_data; @@ -172,6 +177,7 @@ static void _if_focused_revert(Evas_Object *obj, static Evas_Object *_newest_focus_order_get(Evas_Object *obj, unsigned int *newest_focus_order, Eina_Bool can_focus_only); +static double _direction_weight_get(const Evas_Object *obj1, const Evas_Object *obj2, double degree); /* local subsystem globals */ static Evas_Smart *_e_smart = NULL; @@ -727,6 +733,28 @@ elm_widget_focus_next_hook_set(Evas_Object *obj, sd->focus_next_func = func; } +/** + * @internal + * + * Set hook to get near object in one direction. + * + * @param obj The widget object. + * @param func The hook to be used with this widget. + * + * @ingroup Widget + */ +EAPI void +elm_widget_focus_direction_hook_set(Evas_Object *obj, + Eina_Bool (*func)(const Evas_Object *obj, + const Evas_Object *base, + double degree, + Evas_Object **direction, + double *weight)) +{ + API_ENTRY return; + sd->focus_direction_func = func; +} + /** * Returns the widget's mirrored mode. * @@ -1641,26 +1669,156 @@ elm_widget_focus_cycle(Evas_Object *obj, /** * @internal * - * Give focus to near object in one direction. + * Give focus to near object(in object tree) in one direction. * - * Give focus to near object in direction of one object. - * If none focusable object in given direction, the focus will not change. + * Give focus to near object(in object tree) in direction of current focused object. + * If none focusable object in given direction or none focused object in object tree, + * the focus will not change. * * @param obj The reference widget - * @param x Horizontal component of direction to focus - * @param y Vertical component of direction to focus + * @param degree Degree changes clockwise. i.e. 0-degree: Up, + * 90-degree: Right, 180-degree: Down, and 270-degree: Left + * @return EINA_TRUE if focus is moved. * * @ingroup Widget */ -//FIXME: If x, y indicates the elements of the directional vector, -//It would be better if these values are the normalized value(float x, float y) -//or degree. -EINA_DEPRECATED EAPI void -elm_widget_focus_direction_go(Evas_Object *obj __UNUSED__, - int x __UNUSED__, - int y __UNUSED__) +EAPI Eina_Bool +elm_widget_focus_direction_go(Evas_Object *obj, double degree) { - return; /* TODO */ + Evas_Object *target = NULL; + Evas_Object *current_focused = NULL; + double weight = 0.0; + + if (!_elm_widget_is(obj)) return EINA_FALSE; + if (!elm_widget_focus_get(obj)) return EINA_FALSE; + + current_focused = elm_widget_focused_object_get(obj); + + if (elm_widget_focus_direction_get(obj, current_focused, degree, &target, &weight)) + { + elm_widget_focus_steal(target); + return EINA_TRUE; + } + return EINA_FALSE; +} + +/** + * @internal + * + * Get near object in one direction of base object. + * + * Get near object(in the object sub-tree) in one direction of + * base object. Return the near object by reference. + * By initializing weight, you can filter objects locating far + * from base object. If object is in the specific direction, + * weight is (1/(distance^2)). If object is not exactly in one + * direction, some penalty will be added. + * + * @param obj The widget root of sub-tree + * @param base The base object of the direction + * @param degree Degree changes clockwise. i.e. 0-degree: Up, + * 90-degree: Right, 180-degree: Down, and 270-degree: Left + * @param direction The near object in one direction + * @param weight The weight is bigger when the object is located near + * @return EINA_TRUE if near object is updated. + * + * @ingroup Widget + */ +EAPI Eina_Bool +elm_widget_focus_direction_get(const Evas_Object *obj, + const Evas_Object *base, + double degree, + Evas_Object **direction, + double *weight) +{ + API_ENTRY return EINA_FALSE; + + /* -1 means the best was already decided. Don't need any more searching. */ + if (!direction || !weight || !base || (obj == base)) + return EINA_FALSE; + + /* Ignore if disabled */ + if ((!evas_object_visible_get(obj)) + || (elm_widget_disabled_get(obj)) + || (elm_widget_tree_unfocusable_get(obj))) + return EINA_FALSE; + + /* Try use hook */ + if (sd->focus_direction_func) + return sd->focus_direction_func(obj, base, degree, direction, weight); + + if (!elm_widget_can_focus_get(obj) || elm_widget_focus_get(obj)) + return EINA_FALSE; + + double c_weight = _direction_weight_get(base, obj, degree); + if ((c_weight == -1.0) || ((c_weight != 0.0) && (*weight != -1.0) && + ((int)(*weight * 1000000) <= (int)(c_weight * 1000000)))) + { + if ((int)(*weight * 1000000) == (int)(c_weight * 1000000)) + { + Smart_Data *sd1 = evas_object_smart_data_get(*direction); + if (sd1) + { + if (sd->focus_order <= sd1->focus_order) + return EINA_FALSE; + } + } + *direction = (Evas_Object *)obj; + *weight = c_weight; + return EINA_TRUE; + } + return EINA_FALSE; +} + +/** + * @internal + * + * Get near object in one direction of base object in list. + * + * Get near object in one direction of base object in the specific + * object list. Return the near object by reference. + * By initializing weight, you can filter objects locating far + * from base object. If object is in the specific direction, + * weight is (1/(distance^2)). If object is not exactly in one + * direction, some penalty will be added. + * + * @param obj The widget root of sub-tree + * @param base The base object of the direction + * @param items list with ordered objects + * @param list_data_get function to get the object from one item of list + * @param degree Degree changes clockwise. i.e. 0-degree: Up, + * 90-degree: Right, 180-degree: Down, and 270-degree: Left + * @param direction The near object in one direction + * @param weight The weight is bigger when the object is located near + * @return EINA_TRUE if near object is updated. + * + * @ingroup Widget + */ +EAPI Eina_Bool +elm_widget_focus_list_direction_get(const Evas_Object *obj, + const Evas_Object *base, + const Eina_List *items, + void *(*list_data_get)(const Eina_List *list), + double degree, + Evas_Object **direction, + double *weight) +{ + API_ENTRY return EINA_FALSE; + if (!direction || !weight || !base || !items) + return EINA_FALSE; + + const Eina_List *l = items; + Evas_Object *current_best = *direction; + + for (; l; l = eina_list_next(l)) + { + Evas_Object *cur = list_data_get(l); + elm_widget_focus_direction_get(cur, base, degree, direction, weight); + } + if (current_best != *direction) + return EINA_TRUE; + else + return EINA_FALSE; } /** @@ -3609,6 +3767,285 @@ _if_focused_revert(Evas_Object *obj, } } +#define _R(x) (int)((x + 0.05) * 10.0) + +static double +_direction_weight_get(const Evas_Object *obj1, const Evas_Object *obj2, double degree) +{ + Evas_Coord obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2; + double x1, yy1, x2, yy2, xx1, yyy1, xx2, yyy2; + double ax, ay, cx, cy; + double weight = -1.0, g = 0.0; + + if (obj1 == obj2) return 0.0; + + degree -= 90.0; + while (degree >= 360.0) + degree -= 360.0; + while (degree < 0.0) + degree += 360.0; + + evas_object_geometry_get(obj1, &obj_x1, &obj_y1, &w1, &h1); + cx = obj_x1 + (w1 / 2.0); + cy = obj_y1 + (h1 / 2.0); + evas_object_geometry_get(obj2, &obj_x2, &obj_y2, &w2, &h2); + + if (ELM_RECTS_INTERSECT(obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2)) // For overlapping cases. + return 0.0; + + /* Change all points to relative one. */ + x1 = obj_x1 - cx; + xx1 = x1 + w1; + yy1 = obj_y1 - cy; + yyy1 = yy1 + h1; + x2 = obj_x2 - cx; + xx2 = x2 + w2; + yy2 = obj_y2 - cy; + yyy2 = yy2 + h2; + + /* Get crossing points (ax, ay) between obj1 and a line extending to the direction of current degree. */ + if (degree == 0.0) + { + ax = xx1; + ay = 0.0; + } + else if (degree == 90.0) + { + ax = 0.0; + ay = yyy1; + } + else if (degree == 180.0) + { + ax = x1; + ay = 0.0; + } + else if (degree == 270.0) + { + ax = 0.0; + ay = yy1; + } + else + { + g = tan(degree * (M_PI / 180.0)); + if ((degree > 0.0) && (degree < 90.0)) + { + ay = g * xx1; + if (ay <= yyy1) ax = xx1; + else + { + ax = yyy1 / g; + ay = yyy1; + } + } + else if ((degree > 90.0) && (degree < 180.0)) + { + ay = g * x1; + if (ay <= yyy1) ax = x1; + else + { + ax = yyy1 / g; + ay = yyy1; + } + } + else if ((degree > 180.0) && (degree < 270.0)) + { + ay = g * x1; + if (ay >= yy1) ax = x1; + else + { + ax = yy1 / g; + ay = yy1; + } + } + else + { + ay = g * xx1; + if (ay >= yy1) ax = xx1; + else + { + ax = yy1 / g; + ay = yy1; + } + } + } + + /* Filter obj2, if it is not in the specific derection. */ + int i = 0; + double rx[4] = {0.0, 0.0, 0.0, 0.0}, ry[4] = {0.0, 0.0, 0.0, 0.0}; + double t1, t2, u1, v1, u2, v2; + + if ((degree == 45.0) || (degree == 225.0) || (degree == 135.0) || (degree == 315.0)) + { + u1 = 1.0; + v1 = 0.0; + u2 = 0.0; + v2 = 1.0; + } + else + { + double g2 = tan((degree + 45.0) * (M_PI / 180.0)); + u1 = (-1.0 * g2); + u2 = (1.0 / g2); + v1 = v2 = 1.0; + } + t1 = (u1 * ax) + (v1 * ay); + t2 = (u2 * ax) + (v2 * ay); + + if ((_R(t1 * ((u1 * x2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * x2) + (v2 * yy2))) > 0)) + { + rx[i] = x2; + ry[i++] = yy2; + } + if ((_R(t1 * ((u1 * x2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * x2) + (v2 * yyy2))) > 0)) + { + rx[i] = x2; + ry[i++] = yyy2; + } + if ((_R(t1 * ((u1 * xx2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * xx2) + (v2 * yy2))) > 0)) + { + rx[i] = xx2; + ry[i++] = yy2; + } + if ((_R(t1 * ((u1 * xx2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * xx2) + (v2 * yyy2))) > 0)) + { + rx[i] = xx2; + ry[i++] = yyy2; + } + if (i == 0) + { + if (degree == 0.0) + { + if ((_R(xx2) < 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0; + } + else if (degree == 90.0) + { + if ((_R(yyy2) < 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0; + } + else if (degree == 180.0) + { + if ((_R(x2) > 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0; + } + else if (degree == 270.0) + { + if ((_R(yy2) > 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0; + } + else + { + if ((_R(g * x2) >= _R(yy2)) && (_R((g * x2)) <= _R(yyy2))) + { + if (!((_R(ax * x2) > 0) && (_R(ay * (g * x2)) > 0))) return 0.0; + } + else if ((_R(g * xx2) >= _R(yy2)) && (_R((g * xx2)) <= _R(yyy2))) + { + if (!((_R(ax * xx2) > 0) && (_R(ay * (g * xx2)) > 0))) return 0.0; + } + else if ((_R((1.0 / g) * yy2) >= _R(xx2)) && (_R((1.0 / g) * yy2) <= _R(xx2))) + { + if (!((_R(ax * ((1.0 / g) * yy2)) > 0) && (_R(ay * yy2) > 0))) return 0.0; + } + else if ((_R((1.0 / g) * yyy2) >= _R(xx2)) && (_R((1.0 / g) * yyy2) <= _R(xx2))) + { + if (!((_R(ax * ((1.0 / g) * yyy2)) > 0) && (_R(ay * yyy2) > 0))) return 0.0; + } + else return 0.0; + } + } + + /* Calculate the weight for obj2. */ + if (degree == 0.0) + { + if (_R(xx1) > _R(x2)) weight = -1.0; + else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1))) weight = (x2 - xx1) * (x2 - xx1); + else if (_R(yy2) > 0) weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2); + else if (_R(yyy2) < 0) weight = ((x2 - xx1) * (x2 - xx1)) + (yyy2 * yyy2); + else weight = (x2 - xx1) * (x2 - xx1); + } + else if (degree == 90.0) + { + if (_R(yyy1) > _R(yy2)) weight = -1.0; + else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1))) weight = (yy2 - yyy1) * (yy2 - yyy1); + else if (_R(x2) > 0) weight = (x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1)); + else if (_R(xx2) < 0) weight = (xx2 * xx2) + ((yy2 - yyy1) * (yy2 - yyy1)); + else weight = (yy2 - yyy1) * (yy2 - yyy1); + } + else if (degree == 180.0) + { + if (_R(x1) < _R(xx2)) weight = -1.0; + else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1))) weight = (x1 - xx2) * (x1 - xx2); + else if (_R(yy2) > 0) weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2); + else if (_R(yyy2) < 0) weight = ((x1 - xx2) * (x1 - xx2)) + (yyy2 * yyy2); + else weight = (x1 - xx2) * (x1 - xx2); + } + else if (degree == 270.0) + { + if (_R(yy1) < _R(yyy2)) weight = -1.0; + else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1))) weight = (yy1 - yyy2) * (yy1 - yyy2); + else if (_R(x2) > 0) weight = (x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2)); + else if (_R(xx2) < 0) weight = (xx2 * xx2) + ((yy1 - yyy2) * (yy1 - yyy2)); + else weight = (yy1 - yyy2) * (yy1 - yyy2); + } + else + { + int j = 0, k = 0; + double sx[4] = {0.0, 0.0, 0.0, 0.0}, sy[4] = {0.0, 0.0, 0.0, 0.0}; + double t_weight[4] = {-1.0 , -1.0, -1.0, -1.0}; + if ((_R(g * x2) >= _R(yy2)) && (_R(g * x2) <= _R(yyy2))) + { + sx[j] = x2; + sy[j] = g * x2; + t_weight[j++] = ((ax - x2) * (ax - x2)) + ((ay - (g * x2)) * (ay - (g * x2))); + } + if ((_R(g * xx2) >= _R(yy2)) && (_R(g * xx2) <= _R(yyy2))) + { + sx[j] = xx2; + sy[j] = g * xx2; + t_weight[j++] = ((ax - xx2) * (ax - xx2)) + ((ay - (g * xx2)) * (ay - (g * xx2))); + } + if ((_R((1.0 / g) * yy2) >= _R(x2)) && (_R((1.0 / g) * yy2) <= _R(xx2))) + { + sx[j] = (1.0 / g) * yy2; + sy[j] = yy2; + t_weight[j++] = ((ax - ((1.0 / g) * yy2)) * (ax - ((1.0 / g) * yy2))) + ((ay - yy2) * (ay - yy2)); + } + if ((_R((1.0 / g) * yyy2) >= _R(x2)) && (_R((1.0 / g) * yyy2) <= _R(xx2))) + { + sx[j] = (1.0 / g) * yyy2; + sy[j] = yyy2; + t_weight[j++] = ((ax - ((1.0 / g) * yyy2)) * (ax - ((1.0 / g) * yyy2))) + ((ay - yyy2) * (ay - yyy2)); + } + + if((j > 2) || ((j == 2) && ((_R(sx[0]) != _R(sx[1])) || (_R(sy[0]) != _R(sy[1]))))) + { + for (; k < j; k++) + { + if (_R(t_weight[k]) == 0) return -1.0; + if ((1 / weight) < (1 / t_weight[k])) weight = t_weight[k]; + } + } + else + { + for (; k < i; k++) + { + double ccx, ccy, t1_weight, x_diff, y_diff; + ccx = ((1.0 / g) * rx[k] + ry[k]) / (g + (1.0 / g)); + ccy = g * ccx; + x_diff = rx[k] - ccx; + if (x_diff < 0) x_diff *= -1.0; + y_diff = ry[k] - ccy; + if (y_diff < 0) y_diff *= -1.0; + t1_weight = (((ax - ccx) * (ax - ccx)) + ((ay - ccy) * (ay - ccy))) + + ((x_diff * x_diff * x_diff) + (y_diff * y_diff * y_diff)); + if ((_R(t1_weight) != 0) && ((1 / weight) < (1 / t1_weight))) + weight = t1_weight; + } + } + } + /* Return the current object's weight. */ + if (weight == -1.0) return 0.0; + if (_R(weight) == 0) return -1.0; + return (1.0 / weight); +} + static void _smart_del(Evas_Object *obj) { diff --git a/legacy/elementary/src/lib/elm_widget.h b/legacy/elementary/src/lib/elm_widget.h index 2f00121093..2ecadef69b 100644 --- a/legacy/elementary/src/lib/elm_widget.h +++ b/legacy/elementary/src/lib/elm_widget.h @@ -313,6 +313,7 @@ EAPI void elm_widget_on_focus_hook_set(Evas_Object *obj, void (*func EAPI void elm_widget_on_change_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data); EAPI void elm_widget_on_show_region_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data); EAPI void elm_widget_focus_region_hook_set(Evas_Object *obj, void (*func)(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)); +EAPI void elm_widget_focus_direction_hook_set(Evas_Object *obj, Eina_Bool (*func)(const Evas_Object *obj, const Evas_Object *base, double degree, Evas_Object **direction, double *weight)); EAPI void elm_widget_text_set_hook_set(Evas_Object *obj, Elm_Widget_Text_Set_Cb func); #define elm_widget_text_set_hook_set(obj, func) elm_widget_text_set_hook_set(obj, (Elm_Widget_Text_Set_Cb)(func)) EAPI void elm_widget_text_get_hook_set(Evas_Object *obj, Elm_Widget_Text_Get_Cb func); @@ -358,8 +359,10 @@ EAPI const Eina_List *elm_widget_focus_custom_chain_get(const Evas_Object *obj); EAPI void elm_widget_focus_custom_chain_append(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child); EAPI void elm_widget_focus_custom_chain_prepend(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child); EAPI void elm_widget_focus_cycle(Evas_Object *obj, Elm_Focus_Direction dir); -EAPI void elm_widget_focus_direction_go(Evas_Object *obj, int x, int y); +EAPI Eina_Bool elm_widget_focus_direction_go(Evas_Object *obj, double degree); +EAPI Eina_Bool elm_widget_focus_direction_get(const Evas_Object *obj, const Evas_Object *base, double degree, Evas_Object **direction, double *weight); EAPI Eina_Bool elm_widget_focus_next_get(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next); +EAPI Eina_Bool elm_widget_focus_list_direction_get(const Evas_Object *obj, const Evas_Object *base, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), double degree, Evas_Object **direction, double *weight); EAPI Eina_Bool elm_widget_focus_list_next_get(const Evas_Object *obj, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), Elm_Focus_Direction dir, Evas_Object **next); EAPI void elm_widget_focus_set(Evas_Object *obj, int first); EAPI void elm_widget_focused_object_clear(Evas_Object *obj); diff --git a/legacy/elementary/src/lib/elm_win.c b/legacy/elementary/src/lib/elm_win.c index 400d6691ec..7b859273ae 100644 --- a/legacy/elementary/src/lib/elm_win.c +++ b/legacy/elementary/src/lib/elm_win.c @@ -522,6 +522,32 @@ _elm_win_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_O return EINA_FALSE; } +static Eina_Bool +_elm_win_focus_direction_hook(const Evas_Object *obj, const Evas_Object *base, double degree, + Evas_Object **direction, double *weight) +{ + Elm_Win *wd = elm_widget_data_get(obj); + const Eina_List *items; + const Eina_List *list; + void *(*list_data_get) (const Eina_List *list); + + if (!wd) + return EINA_FALSE; + list = elm_widget_sub_object_list_get(obj); + + /* Focus chain */ + if (list) + { + if (!(items = elm_widget_focus_custom_chain_get(obj))) + items = list; + + list_data_get = eina_list_data_get; + + return elm_widget_focus_list_direction_get(obj, base, items, list_data_get, degree, direction, weight); + } + return EINA_FALSE; +} + static void _elm_win_on_focus_hook(void *data __UNUSED__, Evas_Object *obj) { @@ -540,6 +566,9 @@ _elm_win_event_cb(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_T if (type == EVAS_CALLBACK_KEY_DOWN) { Evas_Event_Key_Down *ev = event_info; + Evas_Object *current_focused; + + current_focused = elm_widget_focused_object_get(obj); if (!strcmp(ev->keyname, "Tab")) { if (evas_key_modifier_is_set(ev->modifiers, "Shift")) @@ -552,22 +581,34 @@ _elm_win_event_cb(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_T else if ((!strcmp(ev->keyname, "Left")) || ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string))) { - //TODO : woohyun jung + if (current_focused == obj) + elm_widget_focus_cycle(obj, ELM_FOCUS_NEXT); + else + elm_widget_focus_direction_go(obj, 270.0); } else if ((!strcmp(ev->keyname, "Right")) || ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string))) { - //TODO : woohyun jung + if (current_focused == obj) + elm_widget_focus_cycle(obj, ELM_FOCUS_NEXT); + else + elm_widget_focus_direction_go(obj, 90.0); } else if ((!strcmp(ev->keyname, "Up")) || ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string))) { - //TODO : woohyun jung + if (current_focused == obj) + elm_widget_focus_cycle(obj, ELM_FOCUS_NEXT); + else + elm_widget_focus_direction_go(obj, 0.0); } else if ((!strcmp(ev->keyname, "Down")) || ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string))) { - //TODO : woohyun jung + if (current_focused == obj) + elm_widget_focus_cycle(obj, ELM_FOCUS_NEXT); + else + elm_widget_focus_direction_go(obj, 180.0); } } @@ -1980,6 +2021,7 @@ elm_win_add(Evas_Object *parent, const char *name, Elm_Win_Type type) elm_widget_can_focus_set(win->win_obj, EINA_TRUE); elm_widget_highlight_ignore_set(win->win_obj, EINA_TRUE); elm_widget_focus_next_hook_set(win->win_obj, _elm_win_focus_next_hook); + elm_widget_focus_direction_hook_set(win->win_obj, _elm_win_focus_direction_hook); evas_object_color_set(win->win_obj, 0, 0, 0, 0); evas_object_move(win->win_obj, 0, 0); evas_object_resize(win->win_obj, 1, 1);