12c40c777e0005cf30852c5b1501528d4c870bb0
[framework/uifw/elementary.git] / src / lib / elm_access.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Mod_Api Mod_Api;
5
6 struct _Mod_Api
7 {
8    void (*out_read) (const char *txt);
9    void (*out_read_done) (void);
10    void (*out_cancel) (void);
11    void (*out_done_callback_set) (void (*func) (void *data), const void *data);
12 };
13
14 static int initted = 0;
15 static Mod_Api *mapi = NULL;
16
17 static void
18 _access_init(void)
19 {
20    Elm_Module *m;
21    initted++;
22    if (initted > 1) return;
23    if (!(m = _elm_module_find_as("access/api"))) return;
24    m->api = malloc(sizeof(Mod_Api));
25    if (!m->api) return;
26    m->init_func(m);
27    ((Mod_Api *)(m->api)      )->out_read = // called to read out some text
28       _elm_module_symbol_get(m, "out_read");
29    ((Mod_Api *)(m->api)      )->out_read_done = // called to set a done marker so when it is reached the done callback is called
30       _elm_module_symbol_get(m, "out_read_done");
31    ((Mod_Api *)(m->api)      )->out_cancel = // called to read out some text
32       _elm_module_symbol_get(m, "out_cancel");
33    ((Mod_Api *)(m->api)      )->out_done_callback_set = // called when last read done
34       _elm_module_symbol_get(m, "out_done_callback_set");
35    mapi = m->api;
36 }
37
38 static Elm_Access_Item *
39 _access_add_set(Elm_Access_Info *ac, int type)
40 {
41    Elm_Access_Item *ai;
42    Eina_List *l;
43
44    if (!ac) return NULL;
45    EINA_LIST_FOREACH(ac->items, l, ai)
46      {
47         if (ai->type == type)
48           {
49              if (!ai->func)
50                {
51                   if (ai->data) eina_stringshare_del(ai->data);
52                }
53              ai->func = NULL;
54              ai->data = NULL;
55              return ai;
56           }
57      }
58    ai = calloc(1, sizeof(Elm_Access_Item));
59    ai->type = type;
60    ac->items = eina_list_prepend(ac->items, ai);
61    return ai;
62 }
63
64 static Eina_Bool
65 _access_obj_over_timeout_cb(void *data)
66 {
67    Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
68    if (!ac) return EINA_FALSE;
69    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
70      {
71         _elm_access_object_hilight(data);
72         _elm_access_read(ac, ELM_ACCESS_CANCEL, data, NULL);
73         _elm_access_read(ac, ELM_ACCESS_TYPE,   data, NULL);
74         _elm_access_read(ac, ELM_ACCESS_INFO,   data, NULL);
75         _elm_access_read(ac, ELM_ACCESS_STATE,  data, NULL);
76         _elm_access_read(ac, ELM_ACCESS_DONE,   data, NULL);
77      }
78    ac->delay_timer = NULL;
79    return EINA_FALSE;
80 }
81
82 static void
83 _access_obj_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
84 {
85    Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
86    if (!ac) return;
87
88    if (ac->delay_timer)
89      {
90         ecore_timer_del(ac->delay_timer);
91         ac->delay_timer = NULL;
92      }
93    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
94       ac->delay_timer = ecore_timer_add(0.2, _access_obj_over_timeout_cb, data);
95 }
96
97 static void
98 _access_obj_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
99 {
100    Elm_Access_Info *ac = evas_object_data_get(data, "_elm_access");
101    if (!ac) return;
102    _elm_access_object_unhilight(data);
103    if (ac->delay_timer)
104      {
105         ecore_timer_del(ac->delay_timer);
106         ac->delay_timer = NULL;
107      }
108 }
109
110 static void
111 _access_obj_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
112 {
113    Elm_Access_Info *ac;
114
115    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_IN,
116                                        _access_obj_mouse_in_cb, data);
117    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_OUT,
118                                        _access_obj_mouse_out_cb, data);
119    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
120                                        _access_obj_del_cb, data);
121    ac = evas_object_data_get(data, "_elm_access");
122    evas_object_data_del(data, "_elm_access");
123    if (ac)
124      {
125         _elm_access_clear(ac);
126         free(ac);
127      }
128 }
129
130 static void
131 _access_read_done(void *data __UNUSED__)
132 {
133    printf("read done\n");
134    // FIXME: produce event here
135 }
136
137 static void
138 _access_2nd_click_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
139 {
140    Ecore_Timer *t;
141
142    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
143                                        _access_2nd_click_del_cb, NULL);
144    t = evas_object_data_get(obj, "_elm_2nd_timeout");
145    if (t)
146      {
147         ecore_timer_del(t);
148         evas_object_data_del(obj, "_elm_2nd_timeout");
149      }
150 }
151
152 static Eina_Bool
153 _access_2nd_click_timeout_cb(void *data)
154 {
155    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
156                                        _access_2nd_click_del_cb, NULL);
157    evas_object_data_del(data, "_elm_2nd_timeout");
158    return EINA_FALSE;
159 }
160
161 static void
162 _access_obj_hilight_del_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
163 {
164    _elm_access_object_hilight_disable(e);
165 }
166
167 static void
168 _access_obj_hilight_hide_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
169 {
170    _elm_access_object_hilight_disable(e);
171 }
172
173 static void
174 _access_obj_hilight_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
175 {
176    Evas_Coord x, y;
177    Evas_Object *o;
178
179    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
180    if (!o) return;
181    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
182    evas_object_move(o, x, y);
183 }
184
185 static void
186 _access_obj_hilight_resize_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
187 {
188    Evas_Coord w, h;
189    Evas_Object *o;
190
191    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
192    if (!o) return;
193    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
194    evas_object_resize(o, w, h);
195 }
196
197
198
199 //-------------------------------------------------------------------------//
200
201 EAPI void
202 _elm_access_clear(Elm_Access_Info *ac)
203 {
204    Elm_Access_Item *ai;
205
206    if (!ac) return;
207    if (ac->delay_timer)
208      {
209         ecore_timer_del(ac->delay_timer);
210         ac->delay_timer = NULL;
211      }
212    EINA_LIST_FREE(ac->items, ai)
213      {
214         if (!ai->func)
215           {
216              if (ai->data) eina_stringshare_del(ai->data);
217           }
218         free(ai);
219      }
220 }
221
222 EAPI void
223 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
224 {
225    Elm_Access_Item *ai = _access_add_set(ac, type);
226    if (!ai) return;
227    ai->data = eina_stringshare_add(text);
228 }
229
230 EAPI void
231 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Content_Cb func, const void *data)
232 {
233    Elm_Access_Item *ai = _access_add_set(ac, type);
234    if (!ai) return;
235    ai->func = func;
236    ai->data = data;
237 }
238
239 EAPI char *
240 <<<<<<< HEAD
241 _elm_access_text_get(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
242 =======
243 _elm_access_text_get(const Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
244 >>>>>>> remotes/origin/upstream
245 {
246    Elm_Access_Item *ai;
247    Eina_List *l;
248
249    if (!ac) return NULL;
250    EINA_LIST_FOREACH(ac->items, l, ai)
251      {
252         if (ai->type == type)
253           {
254              if (ai->func) return ai->func((void *)(ai->data), obj, item);
255              else if (ai->data) return strdup(ai->data);
256              return NULL;
257           }
258      }
259    return NULL;
260 }
261
262 EAPI void
263 _elm_access_read(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
264 {
265    char *txt = _elm_access_text_get(ac, type, obj, item);
266
267    _access_init();
268    if (mapi)
269      {
270         if (mapi->out_done_callback_set)
271            mapi->out_done_callback_set(_access_read_done, NULL);
272         if (type == ELM_ACCESS_DONE)
273           {
274              if (mapi->out_read_done) mapi->out_read_done();
275           }
276         else if (type == ELM_ACCESS_CANCEL)
277           {
278              if (mapi->out_cancel) mapi->out_cancel();
279           }
280         else
281           {
282              if (txt)
283                {
284                   if (mapi->out_read) mapi->out_read(txt);
285                   if (mapi->out_read) mapi->out_read(".\n");
286                }
287           }
288      }
289    if (txt) free(txt);
290 }
291
292 EAPI void
293 _elm_access_say(const char *txt)
294 {
295    _access_init();
296    if (mapi)
297      {
298         if (mapi->out_done_callback_set)
299            mapi->out_done_callback_set(_access_read_done, NULL);
300         if (mapi->out_cancel) mapi->out_cancel();
301         if (txt)
302           {
303              if (mapi->out_read) mapi->out_read(txt);
304              if (mapi->out_read) mapi->out_read(".\n");
305           }
306         if (mapi->out_read_done) mapi->out_read_done();
307      }
308 }
309
310 EAPI Elm_Access_Info *
311 <<<<<<< HEAD
312 _elm_access_object_get(Evas_Object *obj)
313 =======
314 _elm_access_object_get(const Evas_Object *obj)
315 >>>>>>> remotes/origin/upstream
316 {
317    return evas_object_data_get(obj, "_elm_access");
318 }
319
320 EAPI Elm_Access_Info *
321 <<<<<<< HEAD
322 _elm_access_item_get(Elm_Widget_Item *it)
323 =======
324 _elm_access_item_get(const Elm_Widget_Item *it)
325 >>>>>>> remotes/origin/upstream
326 {
327    return it->access;
328 }
329
330 EAPI void
331 _elm_access_object_hilight(Evas_Object *obj)
332 {
333    Evas_Object *o;
334    Evas_Coord x, y, w, h;
335
336    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
337    if (!o)
338      {
339         o = edje_object_add(evas_object_evas_get(obj));
340         evas_object_name_set(o, "_elm_access_disp");
341         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
342      }
343    else
344      {
345         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
346         if (ptarget)
347           {
348              evas_object_data_del(o, "_elm_access_target");
349              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
350                                                  _access_obj_hilight_del_cb, NULL);
351              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
352                                                  _access_obj_hilight_hide_cb, NULL);
353              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
354                                                  _access_obj_hilight_move_cb, NULL);
355              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
356                                                  _access_obj_hilight_resize_cb, NULL);
357           }
358      }
359    evas_object_data_set(o, "_elm_access_target", obj);
360    _elm_theme_object_set(obj, o, "access", "base", "default");
361    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
362                                   _access_obj_hilight_del_cb, NULL);
363    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
364                                   _access_obj_hilight_hide_cb, NULL);
365    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
366                                   _access_obj_hilight_move_cb, NULL);
367    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
368                                   _access_obj_hilight_resize_cb, NULL);
369    evas_object_raise(o);
370    evas_object_geometry_get(obj, &x, &y, &w, &h);
371    evas_object_move(o, x, y);
372    evas_object_resize(o, w, h);
373    evas_object_show(o);
374 }
375
376 EAPI void
377 _elm_access_object_unhilight(Evas_Object *obj)
378 {
379    Evas_Object *o, *ptarget;
380
381    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
382    if (!o) return;
383    ptarget = evas_object_data_get(o, "_elm_access_target");
384    if (ptarget == obj)
385      {
386         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
387                                             _access_obj_hilight_del_cb, NULL);
388         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
389                                             _access_obj_hilight_hide_cb, NULL);
390         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
391                                             _access_obj_hilight_move_cb, NULL);
392         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
393                                             _access_obj_hilight_resize_cb, NULL);
394         evas_object_del(o);
395      }
396 }
397
398 EAPI void
399 _elm_access_object_hilight_disable(Evas *e)
400 {
401    Evas_Object *o, *ptarget;
402
403    o = evas_object_name_find(e, "_elm_access_disp");
404    if (!o) return;
405    ptarget = evas_object_data_get(o, "_elm_access_target");
406    if (ptarget)
407      {
408         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
409                                             _access_obj_hilight_del_cb, NULL);
410         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
411                                             _access_obj_hilight_hide_cb, NULL);
412         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
413                                             _access_obj_hilight_move_cb, NULL);
414         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
415                                             _access_obj_hilight_resize_cb, NULL);
416      }
417    evas_object_del(o);
418 }
419
420 EAPI void
421 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
422 {
423    Elm_Access_Info *ac;
424
425    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
426                                   _access_obj_mouse_in_cb, obj);
427    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
428                                   _access_obj_mouse_out_cb, obj);
429    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
430                                   _access_obj_del_cb, obj);
431    ac = calloc(1, sizeof(Elm_Access_Info));
432    evas_object_data_set(obj, "_elm_access", ac);
433 }
434
435 static Eina_Bool
436 _access_item_over_timeout_cb(void *data)
437 {
438    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
439    if (!ac) return EINA_FALSE;
440    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
441      {
442         _elm_access_object_hilight(((Elm_Widget_Item *)data)->view);
443         _elm_access_read(ac, ELM_ACCESS_CANCEL, NULL, data);
444         _elm_access_read(ac, ELM_ACCESS_TYPE,   NULL, data);
445         _elm_access_read(ac, ELM_ACCESS_INFO,   NULL, data);
446         _elm_access_read(ac, ELM_ACCESS_STATE,  NULL, data);
447         _elm_access_read(ac, ELM_ACCESS_DONE,   NULL, data);
448      }
449    ac->delay_timer = NULL;
450    return EINA_FALSE;
451 }
452
453 static void
454 _access_item_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
455 {
456    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
457    if (!ac) return;
458
459    if (ac->delay_timer)
460      {
461         ecore_timer_del(ac->delay_timer);
462         ac->delay_timer = NULL;
463      }
464    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
465       ac->delay_timer = ecore_timer_add(0.2, _access_item_over_timeout_cb, data);
466 }
467
468 static void
469 _access_item_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
470 {
471    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
472    if (!ac) return;
473
474    _elm_access_object_unhilight(((Elm_Widget_Item *)data)->view);
475    if (ac->delay_timer)
476      {
477         ecore_timer_del(ac->delay_timer);
478         ac->delay_timer = NULL;
479      }
480 }
481
482 static void
483 _access_item_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
484 {
485    Elm_Access_Info *ac;
486
487    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_IN,
488                                        _access_item_mouse_in_cb, data);
489    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_OUT,
490                                        _access_item_mouse_out_cb, data);
491    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
492                                        _access_item_del_cb, data);
493    ac = ((Elm_Widget_Item *)data)->access;
494    ((Elm_Widget_Item *)data)->access = NULL;
495    if (ac)
496      {
497         _elm_access_clear(ac);
498         free(ac);
499      }
500 }
501
502 EAPI void
503 _elm_access_item_register(Elm_Widget_Item *item, Evas_Object *hoverobj)
504 {
505    Elm_Access_Info *ac;
506
507    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
508                                   _access_item_mouse_in_cb, item);
509    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
510                                   _access_item_mouse_out_cb, item);
511    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
512                                   _access_item_del_cb, item);
513    ac = calloc(1, sizeof(Elm_Access_Info));
514    item->access = ac;
515 }
516
517 EAPI Eina_Bool
518 _elm_access_2nd_click_timeout(Evas_Object *obj)
519 {
520    Ecore_Timer *t;
521
522    t = evas_object_data_get(obj, "_elm_2nd_timeout");
523    if (t)
524      {
525         ecore_timer_del(t);
526         evas_object_data_del(obj, "_elm_2nd_timeout");
527         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
528                                             _access_2nd_click_del_cb, NULL);
529         return EINA_TRUE;
530      }
531    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
532    evas_object_data_set(obj, "_elm_2nd_timeout", t);
533    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
534                                   _access_2nd_click_del_cb, NULL);
535    return EINA_FALSE;
536 }