Hello all ~
I wanna get review of my patch about "focus movement in all directions".
Newly added internal APIs are as follows:
1. elm_widget_focus_direction_go
2. elm_widget_focus_direction_get
3. elm_widget_focus_list_direction_get
4. elm_widget_focus_direction_hook_set
If elm_widget_focus_direction_go is called with specific object and degree,
- 1. check the current focused object in the sub-tree(root is obj).
- 2. Finding near object in the direction of degree in the sub-tree.
- 3. Set focus to near object.
When step 2 is executed, elm_widget_focus_direction_get is called.
In this function, current best(**direction) is competing with current
object(*obj),
and if current object is better(has low weight), then current best is updated.
(current weight is also updated)
When current object is a kind of container (contains several widgets in it),
then _focus_direction_hook(registered by elm_widget_focus_direction_hook_set)
is called,
and in that function elm_widget_focus_list_direction_get can be called if
needed.
If there is anything to be discussed or indicated or blamed ~
please leave comments :)
I'll wait for some days ~ and if there is no comments ~
then commits this patch :)
Thanks !!
Index: ChangeLog
===================================================================
--- ChangeLog (revision 70544)
+++ ChangeLog (working copy)
@@ -12,3 +12,4 @@
2012-04-30 Jérôme Pinot
* Add missing files in the tarballs.
+ * Focus can be moved in all directions by elm_widget_focus_go function.
Index: src/lib/elm_table.c
===================================================================
--- src/lib/elm_table.c (revision 70544)
+++ src/lib/elm_table.c (working copy)
@@ -69,6 +69,43 @@ _elm_table_focus_next_hook(const Evas_Object *obj,
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);
Index: src/lib/elm_frame.c
===================================================================
--- src/lib/elm_frame.c (revision 70544)
+++ src/lib/elm_frame.c (working copy)
@@ -77,6 +77,19 @@ _elm_frame_focus_next_hook(const Evas_Object *obj,
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);
Index: src/lib/elm_win.c
===================================================================
--- src/lib/elm_win.c (revision 70544)
+++ src/lib/elm_win.c (working copy)
@@ -522,6 +522,32 @@ _elm_win_focus_next_hook(const Evas_Object *obj, E
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 *s
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 *s
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_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);
Index: src/lib/elm_layout.c
===================================================================
--- src/lib/elm_layout.c (revision 70544)
+++ src/lib/elm_layout.c (working copy)
@@ -180,6 +180,32 @@ _elm_layout_focus_next_hook(const Evas_Object *obj
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);
Index: src/lib/elm_scroller.c
===================================================================
--- src/lib/elm_scroller.c (revision 70544)
+++ src/lib/elm_scroller.c (working copy)
@@ -68,31 +68,134 @@ _event_hook(Evas_Object *obj, Evas_Object *src __U
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")) ||
Index: src/lib/elm_bubble.c
===================================================================
--- src/lib/elm_bubble.c (revision 70544)
+++ src/lib/elm_bubble.c (working copy)
@@ -213,6 +213,19 @@ _elm_bubble_focus_next_hook(const Evas_Object *obj
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);
Index: src/lib/elm_box.c
===================================================================
--- src/lib/elm_box.c (revision 70544)
+++ src/lib/elm_box.c (working copy)
@@ -127,6 +127,31 @@ _elm_box_focus_next_hook(const Evas_Object *obj, E
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);
Index: src/lib/elm_widget.c
===================================================================
--- src/lib/elm_widget.c (revision 70544)
+++ src/lib/elm_widget.c (working copy)
@@ -9,6 +9,7 @@ static const char SMART_NAME[] = "elm_widget";
#define INTERNAL_ENTRY \
Smart_Data * sd = evas_object_smart_data_get(obj); \
if (!sd) return
+#define _R(x) (int)((x + 0.05) * 10.0)
#undef elm_widget_text_set_hook_set
#undef elm_widget_text_get_hook_set
@@ -60,6 +61,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 +178,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;
@@ -728,6 +735,28 @@ elm_widget_focus_next_hook_set(Evas_Object *obj,
}
/**
+ * @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.
*
* @param obj The widget.
@@ -1641,31 +1670,151 @@ 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 is moving 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 is moving 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 || (*weight == -1.0) || !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) || (*weight < c_weight))
+ {
+ *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 is moving 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;
+}
+
+/**
+ * @internal
+ *
* Get next object in focus chain of object tree.
*
* Get next object in focus chain of one object sub-tree.
@@ -3609,6 +3758,279 @@ _if_focused_revert(Evas_Object *obj,
}
}
+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) > 0) weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2 * yy2);
+ else if (_R(yyy2) < 0) weight = ((x2 - xx1) * (x2 - xx1)) + (-1.0 * yyy2 * yyy2 * yyy2);
+ else weight = (x2 - xx1) * (x2 - xx1);
+ }
+ else if (degree == 90.0)
+ {
+ if (_R(yyy1) > _R(yy2)) weight = -1.0;
+ if (_R(x2) > 0) weight = (x2 * x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1));
+ else if (_R(xx2) < 0) weight = (-1.0 * xx2 * 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) > 0) weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2 * yy2);
+ else if (_R(yyy2) < 0) weight = ((x1 - xx2) * (x1 - xx2)) + (-1.0 * yyy2 * 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) > 0) weight = (x2 * x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2));
+ else if (_R(xx2) < 0) weight = (-1.0 * xx2 * 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;
+ }
+ }
+ }
+
+ 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)
{
Index: src/lib/elm_widget.h
===================================================================
--- src/lib/elm_widget.h (revision 70544)
+++ src/lib/elm_widget.h (working copy)
@@ -313,6 +313,7 @@ EAPI void elm_widget_on_focus_hook_set
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_chai
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);
Index: src/bin/test_focus.c
===================================================================
--- src/bin/test_focus.c (revision 70544)
+++ src/bin/test_focus.c (working copy)
@@ -80,7 +80,7 @@ test_focus(void *data __UNUSED__, Evas_Object *obj
{
Evas_Object *lb = elm_label_add(win);
- elm_object_text_set(lb, "<b>Use Tab or Shift+Tab</b>");
+ elm_object_text_set(lb, "<b>Use Tab or Shift+Tab<br/>or Arrow keys</b>");
evas_object_size_hint_weight_set(lb, 0.0, 0.0);
evas_object_size_hint_align_set(lb, EVAS_HINT_FILL,
EVAS_HINT_FILL);
Index: NEWS
===================================================================
--- NEWS (revision 70544)
+++ NEWS (working copy)
@@ -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.
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel