[Scroller] Fix the calculation double type number. Round off to the nearest whole...
[framework/uifw/elementary.git] / src / lib / elm_access.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_interface_scrollable.h"
4
5 static const char ACCESS_SMART_NAME[] = "elm_access";
6
7 ELM_INTERNAL_SMART_SUBCLASS_NEW
8   (ACCESS_SMART_NAME, _elm_access, Elm_Widget_Smart_Class,
9   Elm_Widget_Smart_Class, elm_widget_smart_class_get, NULL);
10
11 struct _Func_Data
12 {
13    void                *user_data; /* Holds user data to CB */
14    Elm_Access_Action_Cb cb;
15 };
16
17 typedef struct _Func_Data Func_Data;
18
19 struct _Action_Info
20 {
21    Evas_Object      *obj;
22    Func_Data         fn[ELM_ACCESS_ACTION_LAST + 1]; /* Callback for specific action */
23 };
24
25 typedef struct _Action_Info Action_Info;
26
27 static Eina_Bool mouse_event_enable = EINA_TRUE;
28 static Eina_Bool read_mode = EINA_FALSE;
29 static Evas_Coord_Point offset;
30 static Evas_Object *s_parent; /* scrollable parent */
31 static Elm_Access_Action_Type action_type = ELM_ACCESS_ACTION_FIRST;
32
33 static Evas_Object * _elm_access_add(Evas_Object *parent);
34
35 static void
36 _elm_access_smart_add(Evas_Object *obj)
37 {
38    EVAS_SMART_DATA_ALLOC(obj, Elm_Widget_Smart_Data);
39    ELM_WIDGET_CLASS(_elm_access_parent_sc)->base.add(obj);
40
41    elm_widget_can_focus_set(obj, EINA_TRUE);
42 }
43
44 static Eina_Bool
45 _elm_access_smart_on_focus(Evas_Object *obj)
46 {
47    evas_object_focus_set(obj, elm_widget_focus_get(obj));
48
49    return EINA_TRUE;
50 }
51
52 static Eina_Bool
53 _elm_access_smart_activate(Evas_Object *obj, Elm_Activate act)
54 {
55    int type = ELM_ACCESS_ACTION_FIRST;
56
57    Action_Info *a;
58    a = evas_object_data_get(obj, "_elm_access_action_info");
59
60    switch (act)
61      {
62       case ELM_ACTIVATE_DEFAULT:
63         type = ELM_ACCESS_ACTION_ACTIVATE;
64         break;
65
66       case ELM_ACTIVATE_UP:
67         type = ELM_ACCESS_ACTION_VALUE_CHANGE;
68         break;
69
70       case ELM_ACTIVATE_DOWN:
71         type = ELM_ACCESS_ACTION_VALUE_CHANGE;
72         break;
73
74       case ELM_ACTIVATE_RIGHT:
75         break;
76
77       case ELM_ACTIVATE_LEFT:
78         break;
79
80       case ELM_ACTIVATE_BACK:
81         type = ELM_ACCESS_ACTION_BACK;
82         break;
83
84       default:
85         break;
86      }
87
88    if ((a) && (type > ELM_ACCESS_ACTION_FIRST) &&
89               (type < ELM_ACCESS_ACTION_LAST) &&
90               (a->fn[type].cb))
91      {
92         a->fn[type].cb(a->fn[type].user_data, obj, NULL);
93         return EINA_TRUE;
94      }
95
96    /* TODO: deprecate below? and change above with _access_action_callback_call(); */
97    if (act != ELM_ACTIVATE_DEFAULT) return EINA_FALSE;
98
99    Elm_Access_Info *ac = evas_object_data_get(obj, "_elm_access");
100    if (!ac) return EINA_FALSE;
101
102    if (ac->activate)
103      ac->activate(ac->activate_data, ac->part_object,
104                   (Elm_Object_Item *)ac->widget_item);
105
106    return EINA_TRUE;
107 }
108
109 static void
110 _elm_access_smart_set_user(Elm_Widget_Smart_Class *sc)
111 {
112    sc->base.add = _elm_access_smart_add;
113
114    /* not a 'focus chain manager' */
115    sc->focus_next = NULL;
116    sc->focus_direction = NULL;
117    sc->on_focus = _elm_access_smart_on_focus;
118    sc->activate = _elm_access_smart_activate;
119
120    return;
121 }
122
123 typedef struct _Mod_Api Mod_Api;
124
125 struct _Mod_Api
126 {
127    void (*out_read) (const char *txt);
128    void (*out_read_done) (void);
129    void (*out_cancel) (void);
130    void (*out_done_callback_set) (void (*func) (void *data), const void *data);
131 };
132
133 static int initted = 0;
134 static Mod_Api *mapi = NULL;
135
136 static void
137 _access_init(void)
138 {
139    Elm_Module *m;
140    initted++;
141    if (initted > 1) return;
142    if (!(m = _elm_module_find_as("access/api"))) return;
143    m->api = malloc(sizeof(Mod_Api));
144    if (!m->api) return;
145    m->init_func(m);
146    ((Mod_Api *)(m->api)      )->out_read = // called to read out some text
147       _elm_module_symbol_get(m, "out_read");
148    ((Mod_Api *)(m->api)      )->out_read_done = // called to set a done marker so when it is reached the done callback is called
149       _elm_module_symbol_get(m, "out_read_done");
150    ((Mod_Api *)(m->api)      )->out_cancel = // called to read out some text
151       _elm_module_symbol_get(m, "out_cancel");
152    ((Mod_Api *)(m->api)      )->out_done_callback_set = // called when last read done
153       _elm_module_symbol_get(m, "out_done_callback_set");
154    mapi = m->api;
155 }
156
157 static void
158 _access_shutdown(void)
159 {
160    Elm_Module *m;
161    if (initted == 0) return;
162    if (!(m = _elm_module_find_as("access/api"))) return;
163
164    m->shutdown_func(m);
165
166    initted = 0;
167
168    free(mapi);
169    mapi = NULL;
170 }
171
172 static Elm_Access_Item *
173 _access_add_set(Elm_Access_Info *ac, int type)
174 {
175    Elm_Access_Item *ai;
176    Eina_List *l;
177
178    if (!ac) return NULL;
179    EINA_LIST_FOREACH(ac->items, l, ai)
180      {
181         if (ai->type == type)
182           {
183              if (!ai->func)
184                {
185                   if (ai->data) eina_stringshare_del(ai->data);
186                }
187              ai->func = NULL;
188              ai->data = NULL;
189              return ai;
190           }
191      }
192    ai = calloc(1, sizeof(Elm_Access_Item));
193    ai->type = type;
194    ac->items = eina_list_prepend(ac->items, ai);
195    return ai;
196 }
197
198 static Evas_Object *
199 _access_highlight_object_get(Evas_Object *obj)
200 {
201    Evas_Object *o, *ho;
202
203    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
204    if (!o) return NULL;
205
206    ho = evas_object_data_get(o, "_elm_access_target");
207
208    return ho;
209 }
210
211 static void
212 _access_highlight_read(Elm_Access_Info *ac, Evas_Object *obj)
213 {
214    int type;
215    char *txt = NULL;
216    Eina_Strbuf *strbuf;
217
218    /*FIXME: TIZEN only - read at once because Tizen TTS engine performance is not good */
219    strbuf = eina_strbuf_new();
220
221    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
222      {
223
224         if (ac->on_highlight) ac->on_highlight(ac->on_highlight_data);
225         _elm_access_object_hilight(obj);
226
227         for (type = ELM_ACCESS_INFO_FIRST + 1; type < ELM_ACCESS_INFO_LAST; type++)
228           {
229              txt = _elm_access_text_get(ac, type, obj);
230              if (txt && (strlen(txt) > 0))
231                {
232                   if (eina_strbuf_length_get(strbuf) > 0)
233                     eina_strbuf_append_printf(strbuf, ", %s", txt);
234                   else
235                     eina_strbuf_append(strbuf, txt);
236
237                   free(txt);
238                }
239           }
240      }
241
242    txt = eina_strbuf_string_steal(strbuf);
243    eina_strbuf_free(strbuf);
244
245    _elm_access_say(txt);
246    free(txt);
247 }
248
249 static Eina_Bool
250 _access_obj_over_timeout_cb(void *data)
251 {
252    Elm_Access_Info *ac;
253    Evas_Object *ho;
254
255    if (!data) return EINA_FALSE;
256
257    ac = evas_object_data_get(data, "_elm_access");
258    if (!ac) return EINA_FALSE;
259
260    ho = _access_highlight_object_get(data);
261    if (ho != data) _access_highlight_read(ac, data);
262
263    ac->delay_timer = NULL;
264    return EINA_FALSE;
265 }
266
267 static void
268 _access_obj_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
269 {
270    Elm_Access_Info *ac;
271    if (!mouse_event_enable) return;
272
273    ac = evas_object_data_get(data, "_elm_access");
274    if (!ac) return;
275
276    if (ac->delay_timer)
277      {
278         ecore_timer_del(ac->delay_timer);
279         ac->delay_timer = NULL;
280      }
281    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
282       ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
283 }
284
285 static void
286 _access_obj_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
287 {
288    _elm_access_object_unregister(data, obj);
289
290    // _elm_access_edje_object_part_object_register(); set below object data
291    evas_object_data_del(obj, "_part_access_obj");
292 }
293
294 static void
295 _access_read_done(void *data __UNUSED__)
296 {
297    printf("read done\n");
298    // FIXME: produce event here
299 }
300
301 static void
302 _access_2nd_click_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
303 {
304    Ecore_Timer *t;
305
306    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
307                                        _access_2nd_click_del_cb, NULL);
308    t = evas_object_data_get(obj, "_elm_2nd_timeout");
309    if (t)
310      {
311         ecore_timer_del(t);
312         evas_object_data_del(obj, "_elm_2nd_timeout");
313      }
314 }
315
316 static Eina_Bool
317 _access_2nd_click_timeout_cb(void *data)
318 {
319    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
320                                        _access_2nd_click_del_cb, NULL);
321    evas_object_data_del(data, "_elm_2nd_timeout");
322    return EINA_FALSE;
323 }
324
325 static void
326 _access_obj_hilight_del_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
327 {
328    _elm_access_object_hilight_disable(e);
329 }
330
331 static void
332 _access_obj_hilight_hide_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
333 {
334    _elm_access_object_hilight_disable(e);
335 }
336
337 static void
338 _access_obj_hilight_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
339 {
340    Evas_Coord x, y;
341    Evas_Object *o;
342
343    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
344    if (!o) return;
345    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
346    evas_object_move(o, x, y);
347 }
348
349 static void
350 _access_obj_hilight_resize_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
351 {
352    Evas_Coord w, h;
353    Evas_Object *o;
354
355    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
356    if (!o) return;
357    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
358    evas_object_resize(o, w, h);
359 }
360
361 void
362 _elm_access_mouse_event_enabled_set(Eina_Bool enabled)
363 {
364    enabled = !!enabled;
365    if (mouse_event_enable == enabled) return;
366    mouse_event_enable = enabled;
367 }
368
369 void
370 _elm_access_read_mode_set(Eina_Bool enabled)
371 {
372    enabled = !!enabled;
373    if (read_mode == enabled) return;
374    read_mode = enabled;
375 }
376
377 Eina_Bool
378 _elm_access_read_mode_get()
379 {
380    return read_mode;
381 }
382
383 void
384 _elm_access_shutdown()
385 {
386    _access_shutdown();
387 }
388
389 static void
390 _access_order_del_cb(void *data,
391                      Evas *e __UNUSED__,
392                      Evas_Object *obj,
393                      void *event_info __UNUSED__)
394 {
395    Elm_Widget_Item *item = data;
396
397    item->access_order = eina_list_remove(item->access_order, obj);
398 }
399
400 void
401 _elm_access_widget_item_access_order_set(Elm_Widget_Item *item,
402                                               Eina_List *objs)
403 {
404    Eina_List *l;
405    Evas_Object *o;
406
407    if (!item) return;
408
409    _elm_access_widget_item_access_order_unset(item);
410
411    EINA_LIST_FOREACH(objs, l, o)
412      {
413         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
414                                        _access_order_del_cb, item);
415      }
416
417    item->access_order = objs;
418 }
419
420 const Eina_List *
421 _elm_access_widget_item_access_order_get(const Elm_Widget_Item *item)
422 {
423    if (!item) return NULL;
424    return item->access_order;
425 }
426
427 void
428 _elm_access_widget_item_access_order_unset(Elm_Widget_Item *item)
429 {
430    Eina_List *l, *l_next;
431    Evas_Object *o;
432
433    if (!item) return;
434
435    EINA_LIST_FOREACH_SAFE(item->access_order, l, l_next, o)
436      {
437         evas_object_event_callback_del_full
438           (o, EVAS_CALLBACK_DEL, _access_order_del_cb, item);
439         item->access_order = eina_list_remove_list(item->access_order, l);
440      }
441 }
442
443 void
444 _elm_access_highlight_object_scroll(Evas_Object *obj, int type, int x, int y)
445 {
446    Evas *evas;
447    Evas_Object *ho;
448    Evas_Coord_Rectangle ho_area;
449
450    if (!obj) return;
451
452    evas = evas_object_evas_get(obj);
453    if (!evas) return;
454
455    switch (type)
456      {
457       case 0:
458         ho = _access_highlight_object_get(obj);
459         if (!ho)
460           {
461              s_parent = NULL;
462              return;
463           }
464         else
465           {
466              /* find scrollable parent */
467              s_parent = elm_widget_parent_get(ho);
468              while (s_parent)
469                {
470                   if(!!evas_object_smart_interface_get(s_parent, ELM_SCROLLABLE_IFACE_NAME))
471                     break;
472                   s_parent = elm_widget_parent_get(s_parent);
473                }
474
475               if (!s_parent) return;
476
477               ELM_SCROLLABLE_IFACE_GET(s_parent, s_iface);
478               s_iface->repeat_events_set(s_parent, EINA_FALSE);
479
480               evas_object_geometry_get
481                 (ho, &ho_area.x, &ho_area.y, &ho_area.w, &ho_area.h);
482
483               offset.x = x - (ho_area.x + (ho_area.w / 2));
484               offset.y = y - (ho_area.y + (ho_area.h / 2));
485           }
486
487         evas_event_feed_mouse_in(evas, 0, NULL);
488         evas_event_feed_mouse_move(evas, x - offset.x, y - offset.y, 0, NULL);
489         evas_event_feed_mouse_down(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
490         break;
491
492       case 1:
493         if (!s_parent) return;
494         evas_event_feed_mouse_move(evas, x - offset.x, y - offset.y, 0, NULL);
495         break;
496
497       case 2:
498         if (!s_parent) return;
499         evas_event_feed_mouse_up(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
500
501         ELM_SCROLLABLE_IFACE_GET(s_parent, s_iface);
502         s_iface->repeat_events_set(s_parent, EINA_TRUE);
503         break;
504
505       default:
506         break;
507      }
508 }
509
510 static Eina_Bool
511 _access_action_callback_call(Evas_Object *obj,
512                              Elm_Access_Action_Type type,
513                              void *data)
514 {
515    Action_Info *a;
516    Eina_Bool ret;
517
518    ret = EINA_FALSE;
519    a = evas_object_data_get(obj, "_elm_access_action_info");
520
521    if (a && (a->fn[type].cb))
522      ret = a->fn[type].cb(a->fn[type].user_data, obj, data);
523
524    return ret;
525 }
526
527 static Eina_Bool
528 _access_highlight_next_get(Evas_Object *obj, Elm_Focus_Direction dir)
529 {
530    int type;
531    Evas_Object *ho, *parent, *target;
532    Eina_Bool ret;
533
534    target = NULL;
535    ret = EINA_FALSE;
536
537    if (!elm_widget_is(obj)) return ret;
538
539    ho = _access_highlight_object_get(obj);
540    if (!ho) ho = obj;
541
542    parent = ho;
543
544    /* find highlight root */
545    do
546      {
547         ELM_WIDGET_DATA_GET(parent, sd);
548         if (sd->highlight_root)
549           {
550              /* change highlight root */
551              obj = parent;
552              break;
553           }
554         parent = elm_widget_parent_get(parent);
555      }
556    while (parent);
557
558    _elm_access_read_mode_set(EINA_TRUE);
559
560    ret = elm_widget_focus_next_get(obj, dir, &target);
561    if (ret && target)
562      {
563         if (dir == ELM_FOCUS_NEXT)
564           type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
565         else
566           type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
567
568         if (!_access_action_callback_call(ho, type, NULL))
569           {
570              /* change highlight object */
571              action_type = type;
572
573              _elm_access_highlight_set(target);
574
575              action_type = ELM_ACCESS_ACTION_FIRST;
576           }
577      }
578
579    _elm_access_read_mode_set(EINA_FALSE);
580
581    return ret;
582 }
583
584 //-------------------------------------------------------------------------//
585 EAPI void
586 _elm_access_highlight_set(Evas_Object* obj)
587 {
588    Evas *evas;
589    Elm_Access_Info *ac;
590    Evas_Object *ho;
591    Evas_Coord_Point ho_point = { 0, 0 };
592
593    if (!obj) return;
594
595    ho = _access_highlight_object_get(obj);
596    if (ho == obj) return;
597
598    ac = evas_object_data_get(obj, "_elm_access");
599    if (!ac) return;
600
601    _access_highlight_read(ac, obj);
602
603    /* move mouse position to inside of highlight object. if an object has a
604       highlight by highlight_cycle();, the mouse still positions at previous
605       position which would be made by MOUSE_IN event. */
606    evas = evas_object_evas_get(obj);
607    if (!evas) return;
608
609    evas_object_geometry_get(obj, &ho_point.x, &ho_point.y, 0, 0);
610    evas_event_feed_mouse_move(evas, ho_point.x, ho_point.y, 0, NULL);
611 }
612
613 EAPI void
614 _elm_access_clear(Elm_Access_Info *ac)
615 {
616    Elm_Access_Item *ai;
617
618    if (!ac) return;
619    if (ac->delay_timer)
620      {
621         ecore_timer_del(ac->delay_timer);
622         ac->delay_timer = NULL;
623      }
624    EINA_LIST_FREE(ac->items, ai)
625      {
626         if (!ai->func)
627           {
628              if (ai->data) eina_stringshare_del(ai->data);
629           }
630         free(ai);
631      }
632 }
633
634 EAPI void
635 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
636 {
637    Elm_Access_Item *ai = _access_add_set(ac, type);
638    if (!ai) return;
639    ai->func = NULL;
640    ai->data = eina_stringshare_add(text);
641 }
642
643 EAPI void
644 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Info_Cb func, const void *data)
645 {
646    Elm_Access_Item *ai = _access_add_set(ac, type);
647    if (!ai) return;
648    ai->func = func;
649    ai->data = data;
650 }
651
652 EAPI void
653 _elm_access_on_highlight_hook_set(Elm_Access_Info           *ac,
654                                   Elm_Access_On_Highlight_Cb func,
655                                   void                      *data)
656 {
657     if (!ac) return;
658     ac->on_highlight = func;
659     ac->on_highlight_data = data;
660 }
661
662 EAPI void
663 _elm_access_activate_callback_set(Elm_Access_Info           *ac,
664                                   Elm_Access_Activate_Cb     func,
665                                   void                      *data)
666 {
667    if (!ac) return;
668    ac->activate = func;
669    ac->activate_data = data;
670 }
671
672 EAPI void
673 _elm_access_highlight_object_activate(Evas_Object *obj, Elm_Activate act)
674 {
675    Evas_Object *ho;
676
677    ho = _access_highlight_object_get(obj);
678    if (!ho) return;
679
680    switch (act)
681      {
682       case ELM_ACTIVATE_DEFAULT:
683       case ELM_ACTIVATE_UP:
684       case ELM_ACTIVATE_DOWN:
685         _elm_access_read_mode_set(EINA_FALSE);
686
687         if (!elm_object_focus_get(ho))
688         elm_object_focus_set(ho, EINA_TRUE);
689
690         elm_widget_activate(ho, act);
691         break;
692
693       case ELM_ACTIVATE_BACK:
694         elm_widget_activate(ho, act);
695         break;
696
697       default:
698         break;
699      }
700
701    return;
702 }
703
704 EAPI void
705 _elm_access_highlight_cycle(Evas_Object *obj, Elm_Focus_Direction dir)
706 {
707    int type;
708    Evas_Object *ho, *parent;
709
710    ho = _access_highlight_object_get(obj);
711    if (!ho) return;
712
713    parent = ho;
714
715    /* find highlight root */
716    do
717      {
718         ELM_WIDGET_DATA_GET(parent, sd);
719         if (sd->highlight_root)
720           {
721              /* change highlight root */
722              obj = parent;
723              break;
724           }
725         parent = elm_widget_parent_get(parent);
726      }
727    while (parent);
728
729    _elm_access_read_mode_set(EINA_TRUE);
730
731    if (dir == ELM_FOCUS_NEXT)
732      type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
733    else
734      type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
735
736    action_type = type;
737
738    if (!_access_action_callback_call(ho, type, NULL))
739      elm_widget_focus_cycle(obj, dir);
740
741    action_type = ELM_ACCESS_ACTION_FIRST;
742
743    _elm_access_read_mode_set(EINA_FALSE);
744 }
745
746 EAPI char *
747 _elm_access_text_get(const Elm_Access_Info *ac, int type, const Evas_Object *obj)
748 {
749    Elm_Access_Item *ai;
750    Eina_List *l;
751
752    if (!ac) return NULL;
753    EINA_LIST_FOREACH(ac->items, l, ai)
754      {
755         if (ai->type == type)
756           {
757              if (ai->func) return ai->func((void *)(ai->data), (Evas_Object *)obj);
758              else if (ai->data) return strdup(ai->data);
759              return NULL;
760           }
761      }
762    return NULL;
763 }
764
765 EAPI void
766 _elm_access_read(Elm_Access_Info *ac, int type, const Evas_Object *obj)
767 {
768    char *txt = _elm_access_text_get(ac, type, obj);
769
770    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
771
772    _access_init();
773    if (mapi)
774      {
775         if (mapi->out_done_callback_set)
776            mapi->out_done_callback_set(_access_read_done, NULL);
777         if (type == ELM_ACCESS_DONE)
778           {
779              if (mapi->out_read_done) mapi->out_read_done();
780           }
781         else if (type == ELM_ACCESS_CANCEL)
782           {
783              if (mapi->out_cancel) mapi->out_cancel();
784           }
785         else
786           {
787              if (txt && mapi->out_read) mapi->out_read(txt);
788           }
789      }
790    if (txt) free(txt);
791 }
792
793 EAPI void
794 _elm_access_say(const char *txt)
795 {
796    if (!_elm_config->access_mode) return;
797
798    if (txt && strlen(txt) == 0) return; /* Tizen only: TTS engine does not work properly */
799
800    _access_init();
801    if (mapi)
802      {
803         if (mapi->out_done_callback_set)
804            mapi->out_done_callback_set(_access_read_done, NULL);
805         if (mapi->out_cancel) mapi->out_cancel();
806         if (txt)
807           {
808              if (mapi->out_read) mapi->out_read(txt);
809              //if (mapi->out_read) mapi->out_read(".\n"); /* TIZEN only: Tizen TTS engine performance is not good */
810           }
811         if (mapi->out_read_done) mapi->out_read_done();
812      }
813 }
814
815 EAPI Elm_Access_Info *
816 _elm_access_object_get(const Evas_Object *obj)
817 {
818    return evas_object_data_get(obj, "_elm_access");
819 }
820
821 EAPI void
822 _elm_access_object_hilight(Evas_Object *obj)
823 {
824    Evas_Object *o;
825    Evas_Coord x, y, w, h;
826    Elm_Access_Action_Info *a;
827
828    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
829    if (!o)
830      {
831         o = edje_object_add(evas_object_evas_get(obj));
832         evas_object_name_set(o, "_elm_access_disp");
833         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
834      }
835    else
836      {
837         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
838         if (ptarget)
839           {
840              evas_object_data_del(o, "_elm_access_target");
841              elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
842
843              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
844                                                  _access_obj_hilight_del_cb, NULL);
845              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
846                                                  _access_obj_hilight_hide_cb, NULL);
847              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
848                                                  _access_obj_hilight_move_cb, NULL);
849              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
850                                                  _access_obj_hilight_resize_cb, NULL);
851              _access_action_callback_call(ptarget, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
852           }
853      }
854    evas_object_data_set(o, "_elm_access_target", obj);
855    elm_widget_parent_highlight_set(obj, EINA_TRUE);
856
857    elm_widget_theme_object_set(obj, o, "access", "base", "default");
858
859    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
860                                   _access_obj_hilight_del_cb, NULL);
861    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
862                                   _access_obj_hilight_hide_cb, NULL);
863    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
864                                   _access_obj_hilight_move_cb, NULL);
865    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
866                                   _access_obj_hilight_resize_cb, NULL);
867    evas_object_raise(o);
868    evas_object_geometry_get(obj, &x, &y, &w, &h);
869    evas_object_move(o, x, y);
870    evas_object_resize(o, w, h);
871
872    /* use callback, should an access object do below every time when
873         * a window gets a client message ECORE_X_ATOM_E_ILLMUE_ACTION_READ? */
874    a = calloc(1, sizeof(Elm_Access_Action_Info));
875    a->action_type = action_type;
876    if (!_access_action_callback_call(obj, ELM_ACCESS_ACTION_HIGHLIGHT, a))
877      evas_object_show(o);
878    else
879      evas_object_hide(o);
880    free(a);
881 }
882
883 EAPI void
884 _elm_access_object_unhilight(Evas_Object *obj)
885 {
886    Evas_Object *o, *ptarget;
887
888    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
889    if (!o) return;
890    ptarget = evas_object_data_get(o, "_elm_access_target");
891    if (ptarget == obj)
892      {
893         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
894                                             _access_obj_hilight_del_cb, NULL);
895         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
896                                             _access_obj_hilight_hide_cb, NULL);
897         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
898                                             _access_obj_hilight_move_cb, NULL);
899         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
900                                             _access_obj_hilight_resize_cb, NULL);
901         evas_object_del(o);
902         elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
903         _access_action_callback_call(ptarget, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
904      }
905 }
906
907 static void
908 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
909                 void *event_info __UNUSED__)
910 {
911    Evas_Object *accessobj;
912    Evas_Coord w, h;
913
914    accessobj = data;
915    if (!accessobj) return;
916
917    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
918    evas_object_resize(accessobj, w, h);
919 }
920
921 static void
922 _content_move(void *data, Evas *e __UNUSED__, Evas_Object *obj,
923               void *event_info __UNUSED__)
924 {
925    Evas_Object *accessobj;
926    Evas_Coord x, y;
927
928    accessobj = data;
929    if (!accessobj) return;
930
931    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
932    evas_object_move(accessobj, x, y);
933 }
934
935 static Evas_Object *
936 _access_object_register(Evas_Object *obj, Evas_Object *parent)
937 {
938    Evas_Object *ao;
939    Elm_Access_Info *ac;
940    Evas_Coord x, y, w, h;
941
942    if (!obj) return NULL;
943
944    /* create access object */
945    ao = _elm_access_add(parent);
946    if (!ao) return NULL;
947
948    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
949                                   _content_resize, ao);
950    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
951                                   _content_move, ao);
952
953    evas_object_geometry_get(obj, &x, &y, &w, &h);
954    evas_object_move(ao, x, y);
955    evas_object_resize(ao, w, h);
956    evas_object_show(ao);
957
958    /* register access object */
959    _elm_access_object_register(ao, obj);
960
961    /* set access object */
962    evas_object_data_set(obj, "_part_access_obj", ao);
963
964    /* set owner part object */
965    ac = evas_object_data_get(ao, "_elm_access");
966    ac->part_object = obj;
967
968    return ao;
969 }
970
971 static void
972 _access_object_unregister(Evas_Object *obj)
973 {
974    Elm_Access_Info *ac;
975    Evas_Object *ao;
976
977    if (!obj) return;
978
979    ao = evas_object_data_get(obj, "_part_access_obj");
980
981    if (ao)
982      {
983         evas_object_data_del(obj, "_part_access_obj");
984
985         /* delete callbacks */
986         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE,
987                                             _content_resize, ao);
988         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
989                                             _content_move, ao);
990
991         /* unregister access object */
992         _elm_access_object_unregister(ao, obj);
993
994         evas_object_del(ao);
995      }
996    else
997      {
998         /* button, check, label etc. */
999         ac = evas_object_data_get(obj, "_elm_access");
1000         if (ac && ac->hoverobj)
1001           _elm_access_object_unregister(obj, ac->hoverobj);
1002      }
1003 }
1004
1005 EAPI Evas_Object *
1006 _elm_access_edje_object_part_object_register(Evas_Object* obj,
1007                                              const Evas_Object *eobj,
1008                                              const char* part)
1009 {
1010    Evas_Object *ao, *po;
1011
1012    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1013    if (!obj || !po) return NULL;
1014
1015    /* check previous access object */
1016    ao = evas_object_data_get(po, "_part_access_obj");
1017    if (ao)
1018      _elm_access_edje_object_part_object_unregister(obj, eobj, part);
1019
1020    ao = _access_object_register(po, obj);
1021
1022    return ao;
1023 }
1024
1025 //FIXME: unused obj should be removed from here and each widget.
1026 EAPI void
1027 _elm_access_edje_object_part_object_unregister(Evas_Object* obj __UNUSED__,
1028                                                const Evas_Object *eobj,
1029                                                const char* part)
1030 {
1031    Evas_Object *po;
1032
1033    po = (Evas_Object *)edje_object_part_object_get(eobj, part);
1034    if (!po) return;
1035
1036    _access_object_unregister(po);
1037 }
1038
1039 EAPI void
1040 _elm_access_object_hilight_disable(Evas *e)
1041 {
1042    Evas_Object *o, *ptarget;
1043
1044    o = evas_object_name_find(e, "_elm_access_disp");
1045    if (!o) return;
1046    ptarget = evas_object_data_get(o, "_elm_access_target");
1047    if (ptarget)
1048      {
1049         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
1050                                             _access_obj_hilight_del_cb, NULL);
1051         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
1052                                             _access_obj_hilight_hide_cb, NULL);
1053         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
1054                                             _access_obj_hilight_move_cb, NULL);
1055         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
1056                                             _access_obj_hilight_resize_cb, NULL);
1057         elm_widget_parent_highlight_set(ptarget, EINA_FALSE);
1058         _access_action_callback_call(ptarget, ELM_ACCESS_ACTION_UNHIGHLIGHT, NULL);
1059      }
1060    evas_object_del(o);
1061 }
1062
1063 EAPI void
1064 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
1065 {
1066    Elm_Access_Info *ac;
1067
1068    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1069                                   _access_obj_mouse_in_cb, obj);
1070    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
1071                                   _access_obj_del_cb, obj);
1072    ac = calloc(1, sizeof(Elm_Access_Info));
1073    evas_object_data_set(obj, "_elm_access", ac);
1074
1075    ac->hoverobj = hoverobj;
1076 }
1077
1078 EAPI void
1079 _elm_access_object_unregister(Evas_Object *obj, Evas_Object *hoverobj)
1080 {
1081    Elm_Access_Info *ac;
1082
1083    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_MOUSE_IN,
1084                                        _access_obj_mouse_in_cb, obj);
1085    evas_object_event_callback_del_full(hoverobj, EVAS_CALLBACK_DEL,
1086                                        _access_obj_del_cb, obj);
1087
1088    ac = evas_object_data_get(obj, "_elm_access");
1089    evas_object_data_del(obj, "_elm_access");
1090    if (ac)
1091      {
1092         _elm_access_clear(ac);
1093         free(ac);
1094      }
1095
1096    Action_Info *a;
1097    a = evas_object_data_get(obj, "_elm_access_action_info");
1098    if (a) free(a);
1099 }
1100
1101 EAPI void
1102 _elm_access_widget_item_register(Elm_Widget_Item *item)
1103 {
1104    Evas_Object *ao, *ho;
1105    Evas_Coord x, y, w, h;
1106    Elm_Access_Info *ac;
1107
1108    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1109
1110    /* check previous access object */
1111    if (item->access_obj)
1112      _elm_access_widget_item_unregister(item);
1113
1114    // create access object
1115    ho = item->view;
1116    ao = _elm_access_add(item->widget);
1117    if (!ao) return;
1118
1119    evas_object_event_callback_add(ho, EVAS_CALLBACK_RESIZE,
1120                                   _content_resize, ao);
1121    evas_object_event_callback_add(ho, EVAS_CALLBACK_MOVE,
1122                                   _content_move, ao);
1123
1124    evas_object_geometry_get(ho, &x, &y, &w, &h);
1125    evas_object_move(ao, x, y);
1126    evas_object_resize(ao, w, h);
1127    evas_object_show(ao);
1128
1129    // register access object
1130    _elm_access_object_register(ao, ho);
1131
1132    item->access_obj = ao;
1133
1134    /* set owner widget item */
1135    ac = evas_object_data_get(ao, "_elm_access");
1136    ac->widget_item = item;
1137 }
1138
1139 EAPI void
1140 _elm_access_widget_item_unregister(Elm_Widget_Item *item)
1141 {
1142    Evas_Object *ho;
1143
1144    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
1145
1146    if (!item->access_obj) return;
1147
1148    ho = item->view;
1149    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_RESIZE,
1150                                   _content_resize, item->access_obj);
1151    evas_object_event_callback_del_full(ho, EVAS_CALLBACK_MOVE,
1152                                   _content_move, item->access_obj);
1153
1154    _elm_access_object_unregister(item->access_obj, ho);
1155
1156    evas_object_del(item->access_obj);
1157    item->access_obj = NULL;
1158 }
1159
1160 EAPI Eina_Bool
1161 _elm_access_2nd_click_timeout(Evas_Object *obj)
1162 {
1163    Ecore_Timer *t;
1164
1165    t = evas_object_data_get(obj, "_elm_2nd_timeout");
1166    if (t)
1167      {
1168         ecore_timer_del(t);
1169         evas_object_data_del(obj, "_elm_2nd_timeout");
1170         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
1171                                             _access_2nd_click_del_cb, NULL);
1172         return EINA_TRUE;
1173      }
1174    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
1175    evas_object_data_set(obj, "_elm_2nd_timeout", t);
1176    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1177                                   _access_2nd_click_del_cb, NULL);
1178    return EINA_FALSE;
1179 }
1180
1181 static Evas_Object *
1182 _elm_access_add(Evas_Object *parent)
1183 {
1184    Evas_Object *obj;
1185
1186    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1187
1188    obj = elm_widget_add(_elm_access_smart_class_new(), parent);
1189    if (!obj) return NULL;
1190
1191    if (!elm_widget_sub_object_add(parent, obj))
1192      ERR("could not add %p as sub object of %p", obj, parent);
1193
1194    return obj;
1195 }
1196
1197 EAPI Evas_Object *
1198 elm_access_object_register(Evas_Object *obj, Evas_Object *parent)
1199 {
1200    return _access_object_register(obj, parent);
1201 }
1202
1203 EAPI void
1204 elm_access_object_unregister(Evas_Object *obj)
1205 {
1206    _access_object_unregister(obj);
1207 }
1208
1209 EAPI Evas_Object *
1210 elm_access_object_get(const Evas_Object *obj)
1211 {
1212    return evas_object_data_get(obj, "_part_access_obj");
1213 }
1214
1215 EAPI void
1216 elm_access_info_set(Evas_Object *obj, int type, const char *text)
1217 {
1218    _elm_access_text_set(_elm_access_object_get(obj), type, text);
1219 }
1220
1221 EAPI char *
1222 elm_access_info_get(const Evas_Object *obj, int type)
1223 {
1224    return _elm_access_text_get(_elm_access_object_get(obj), type, obj);
1225 }
1226
1227 EAPI void
1228 elm_access_info_cb_set(Evas_Object *obj, int type,
1229                           Elm_Access_Info_Cb func, const void *data)
1230 {
1231    _elm_access_callback_set(_elm_access_object_get(obj), type, func, data);
1232 }
1233
1234 EAPI void
1235 elm_access_activate_cb_set(Evas_Object *obj,
1236                            Elm_Access_Activate_Cb  func, void *data)
1237 {
1238    Elm_Access_Info *ac;
1239
1240    ac = _elm_access_object_get(obj);
1241    if (!ac) return;
1242
1243    ac->activate = func;
1244    ac->activate_data = data;
1245 }
1246
1247 EAPI void
1248 elm_access_say(const char *text)
1249 {
1250    if (!text) return;
1251
1252    _elm_access_say(text);
1253 }
1254
1255 EAPI void
1256 elm_access_highlight_set(Evas_Object* obj)
1257 {
1258    _elm_access_highlight_set(obj);
1259 }
1260
1261 EAPI Eina_Bool
1262 elm_access_action(Evas_Object *obj, const Elm_Access_Action_Type type, void *action_info)
1263 {
1264    Evas *evas;
1265    Evas_Object *ho;
1266    Elm_Access_Action_Info *a;
1267
1268    a = (Elm_Access_Action_Info *) action_info;
1269
1270    switch (type)
1271      {
1272       case ELM_ACCESS_ACTION_READ:
1273       case ELM_ACCESS_ACTION_HIGHLIGHT:
1274         evas = evas_object_evas_get(obj);
1275         if (!evas) return EINA_FALSE;
1276
1277         _elm_access_mouse_event_enabled_set(EINA_TRUE);
1278
1279         evas_event_feed_mouse_in(evas, 0, NULL);
1280         evas_event_feed_mouse_move(evas, a->x, a->y, 0, NULL);
1281         _elm_access_mouse_event_enabled_set(EINA_FALSE);
1282
1283         ho = _access_highlight_object_get(obj);
1284         if (ho)
1285           _access_action_callback_call(ho, ELM_ACCESS_ACTION_READ, a);
1286         break;
1287
1288       case ELM_ACCESS_ACTION_UNHIGHLIGHT:
1289         evas = evas_object_evas_get(obj);
1290         if (!evas) return EINA_FALSE;
1291         _elm_access_object_hilight_disable(evas);
1292         break;
1293
1294       case ELM_ACCESS_ACTION_HIGHLIGHT_NEXT:
1295         if (a->highlight_cycle)
1296           _elm_access_highlight_cycle(obj, ELM_FOCUS_NEXT);
1297         else
1298           return _access_highlight_next_get(obj, ELM_FOCUS_NEXT);
1299         break;
1300
1301       case ELM_ACCESS_ACTION_HIGHLIGHT_PREV:
1302         if (a->highlight_cycle)
1303           _elm_access_highlight_cycle(obj, ELM_FOCUS_PREVIOUS);
1304         else
1305           return _access_highlight_next_get(obj, ELM_FOCUS_PREVIOUS);
1306         break;
1307
1308       case ELM_ACCESS_ACTION_ACTIVATE:
1309         _elm_access_highlight_object_activate(obj, ELM_ACTIVATE_DEFAULT);
1310         break;
1311
1312       case ELM_ACCESS_ACTION_VALUE_CHANGE:
1313         _elm_access_highlight_object_activate(obj, ELM_ACTIVATE_UP);
1314         break;
1315
1316       case ELM_ACCESS_ACTION_SCROLL:
1317         _elm_access_highlight_object_scroll(obj, a->mouse_type, a->x, a->y);
1318         break;
1319
1320       case ELM_ACCESS_ACTION_BACK:
1321         break;
1322
1323       default:
1324         break;
1325      }
1326
1327    return EINA_TRUE;
1328 }
1329
1330 EAPI void
1331 elm_access_action_cb_set(Evas_Object *obj, const Elm_Access_Action_Type type, const Elm_Access_Action_Cb cb, const void *data)
1332 {
1333    Action_Info *a;
1334    a =  evas_object_data_get(obj, "_elm_access_action_info");
1335
1336    if (!a)
1337      {
1338         a = calloc(1, sizeof(Action_Info));
1339         evas_object_data_set(obj, "_elm_access_action_info", a);
1340      }
1341
1342    a->obj = obj;
1343    a->fn[type].cb = cb;
1344    a->fn[type].user_data = (void *)data;
1345 }
1346
1347 EAPI void
1348 elm_access_external_info_set(Evas_Object *obj, const char *text)
1349 {
1350    _elm_access_text_set
1351      (_elm_access_object_get(obj), ELM_ACCESS_CONTEXT_INFO, text);
1352 }
1353
1354 EAPI char *
1355 elm_access_external_info_get(const Evas_Object *obj)
1356 {
1357    Elm_Access_Info *ac;
1358
1359    ac = _elm_access_object_get(obj);
1360    return _elm_access_text_get(ac, ELM_ACCESS_CONTEXT_INFO, obj);
1361 }