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