Merge "[stackicon] remove trailing whitespaces"
[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 _elm_access_text_get(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
241 {
242    Elm_Access_Item *ai;
243    Eina_List *l;
244
245    if (!ac) return NULL;
246    EINA_LIST_FOREACH(ac->items, l, ai)
247      {
248         if (ai->type == type)
249           {
250              if (ai->func) return ai->func((void *)(ai->data), obj, item);
251              else if (ai->data) return strdup(ai->data);
252              return NULL;
253           }
254      }
255    return NULL;
256 }
257
258 EAPI void
259 _elm_access_read(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
260 {
261    char *txt = _elm_access_text_get(ac, type, obj, item);
262
263    _access_init();
264    if (mapi)
265      {
266         if (mapi->out_done_callback_set)
267            mapi->out_done_callback_set(_access_read_done, NULL);
268         if (type == ELM_ACCESS_DONE)
269           {
270              if (mapi->out_read_done) mapi->out_read_done();
271           }
272         else if (type == ELM_ACCESS_CANCEL)
273           {
274              if (mapi->out_cancel) mapi->out_cancel();
275           }
276         else
277           {
278              if (txt)
279                {
280                   if (mapi->out_read) mapi->out_read(txt);
281                   if (mapi->out_read) mapi->out_read(".\n");
282                }
283           }
284      }
285    if (txt) free(txt);
286 }
287
288 EAPI void
289 _elm_access_say(const char *txt)
290 {
291    _access_init();
292    if (mapi)
293      {
294         if (mapi->out_done_callback_set)
295            mapi->out_done_callback_set(_access_read_done, NULL);
296         if (mapi->out_cancel) mapi->out_cancel();
297         if (txt)
298           {
299              if (mapi->out_read) mapi->out_read(txt);
300              if (mapi->out_read) mapi->out_read(".\n");
301           }
302         if (mapi->out_read_done) mapi->out_read_done();
303      }
304 }
305
306 EAPI Elm_Access_Info *
307 _elm_access_object_get(Evas_Object *obj)
308 {
309    return evas_object_data_get(obj, "_elm_access");
310 }
311
312 EAPI Elm_Access_Info *
313 _elm_access_item_get(Elm_Widget_Item *it)
314 {
315    return it->access;
316 }
317
318 EAPI void
319 _elm_access_object_hilight(Evas_Object *obj)
320 {
321    Evas_Object *o;
322    Evas_Coord x, y, w, h;
323
324    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
325    if (!o)
326      {
327         o = edje_object_add(evas_object_evas_get(obj));
328         evas_object_name_set(o, "_elm_access_disp");
329         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
330      }
331    else
332      {
333         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
334         if (ptarget)
335           {
336              evas_object_data_del(o, "_elm_access_target");
337              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
338                                                  _access_obj_hilight_del_cb, NULL);
339              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
340                                                  _access_obj_hilight_hide_cb, NULL);
341              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
342                                                  _access_obj_hilight_move_cb, NULL);
343              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
344                                                  _access_obj_hilight_resize_cb, NULL);
345           }
346      }
347    evas_object_data_set(o, "_elm_access_target", obj);
348    _elm_theme_object_set(obj, o, "access", "base", "default");
349    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
350                                   _access_obj_hilight_del_cb, NULL);
351    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
352                                   _access_obj_hilight_hide_cb, NULL);
353    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
354                                   _access_obj_hilight_move_cb, NULL);
355    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
356                                   _access_obj_hilight_resize_cb, NULL);
357    evas_object_raise(o);
358    evas_object_geometry_get(obj, &x, &y, &w, &h);
359    evas_object_move(o, x, y);
360    evas_object_resize(o, w, h);
361    evas_object_show(o);
362 }
363
364 EAPI void
365 _elm_access_object_unhilight(Evas_Object *obj)
366 {
367    Evas_Object *o, *ptarget;
368
369    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
370    if (!o) return;
371    ptarget = evas_object_data_get(o, "_elm_access_target");
372    if (ptarget == obj)
373      {
374         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
375                                             _access_obj_hilight_del_cb, NULL);
376         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
377                                             _access_obj_hilight_hide_cb, NULL);
378         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
379                                             _access_obj_hilight_move_cb, NULL);
380         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
381                                             _access_obj_hilight_resize_cb, NULL);
382         evas_object_del(o);
383      }
384 }
385
386 EAPI void
387 _elm_access_object_hilight_disable(Evas *e)
388 {
389    Evas_Object *o, *ptarget;
390
391    o = evas_object_name_find(e, "_elm_access_disp");
392    if (!o) return;
393    ptarget = evas_object_data_get(o, "_elm_access_target");
394    if (ptarget)
395      {
396         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
397                                             _access_obj_hilight_del_cb, NULL);
398         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
399                                             _access_obj_hilight_hide_cb, NULL);
400         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
401                                             _access_obj_hilight_move_cb, NULL);
402         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
403                                             _access_obj_hilight_resize_cb, NULL);
404      }
405    evas_object_del(o);
406 }
407
408 EAPI void
409 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
410 {
411    Elm_Access_Info *ac;
412
413    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
414                                   _access_obj_mouse_in_cb, obj);
415    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
416                                   _access_obj_mouse_out_cb, obj);
417    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
418                                   _access_obj_del_cb, obj);
419    ac = calloc(1, sizeof(Elm_Access_Info));
420    evas_object_data_set(obj, "_elm_access", ac);
421 }
422
423 static Eina_Bool
424 _access_item_over_timeout_cb(void *data)
425 {
426    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
427    if (!ac) return EINA_FALSE;
428    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
429      {
430         _elm_access_object_hilight(((Elm_Widget_Item *)data)->view);
431         _elm_access_read(ac, ELM_ACCESS_CANCEL, NULL, data);
432         _elm_access_read(ac, ELM_ACCESS_TYPE,   NULL, data);
433         _elm_access_read(ac, ELM_ACCESS_INFO,   NULL, data);
434         _elm_access_read(ac, ELM_ACCESS_STATE,  NULL, data);
435         _elm_access_read(ac, ELM_ACCESS_DONE,   NULL, data);
436      }
437    ac->delay_timer = NULL;
438    return EINA_FALSE;
439 }
440
441 static void
442 _access_item_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
443 {
444    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
445    if (!ac) return;
446
447    if (ac->delay_timer)
448      {
449         ecore_timer_del(ac->delay_timer);
450         ac->delay_timer = NULL;
451      }
452    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
453       ac->delay_timer = ecore_timer_add(0.2, _access_item_over_timeout_cb, data);
454 }
455
456 static void
457 _access_item_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
458 {
459    Elm_Access_Info *ac = ((Elm_Widget_Item *)data)->access;
460    if (!ac) return;
461
462    _elm_access_object_unhilight(((Elm_Widget_Item *)data)->view);
463    if (ac->delay_timer)
464      {
465         ecore_timer_del(ac->delay_timer);
466         ac->delay_timer = NULL;
467      }
468 }
469
470 static void
471 _access_item_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
472 {
473    Elm_Access_Info *ac;
474
475    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_IN,
476                                        _access_item_mouse_in_cb, data);
477    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_OUT,
478                                        _access_item_mouse_out_cb, data);
479    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
480                                        _access_item_del_cb, data);
481    ac = ((Elm_Widget_Item *)data)->access;
482    ((Elm_Widget_Item *)data)->access = NULL;
483    if (ac)
484      {
485         _elm_access_clear(ac);
486         free(ac);
487      }
488 }
489
490 EAPI void
491 _elm_access_item_register(Elm_Widget_Item *item, Evas_Object *hoverobj)
492 {
493    Elm_Access_Info *ac;
494
495    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
496                                   _access_item_mouse_in_cb, item);
497    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
498                                   _access_item_mouse_out_cb, item);
499    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
500                                   _access_item_del_cb, item);
501    ac = calloc(1, sizeof(Elm_Access_Info));
502    item->access = ac;
503 }
504
505 EAPI Eina_Bool
506 _elm_access_2nd_click_timeout(Evas_Object *obj)
507 {
508    Ecore_Timer *t;
509
510    t = evas_object_data_get(obj, "_elm_2nd_timeout");
511    if (t)
512      {
513         ecore_timer_del(t);
514         evas_object_data_del(obj, "_elm_2nd_timeout");
515         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
516                                             _access_2nd_click_del_cb, NULL);
517         return EINA_TRUE;
518      }
519    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
520    evas_object_data_set(obj, "_elm_2nd_timeout", t);
521    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
522                                   _access_2nd_click_del_cb, NULL);
523    return EINA_FALSE;
524 }