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