and hide hilight on mouse out
[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 }
137
138 static void
139 _access_obj_hilight_del_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
140 {
141    _elm_access_object_hilight_disable(e);
142 }
143
144 static void
145 _access_obj_hilight_hide_cb(void *data __UNUSED__, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
146 {
147    _elm_access_object_hilight_disable(e);
148 }
149
150 static void
151 _access_obj_hilight_move_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
152 {
153    Evas_Coord x, y;
154    Evas_Object *o;
155    
156    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
157    if (!o) return;
158    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
159    evas_object_move(o, x, y);
160 }
161
162 static void
163 _access_obj_hilight_resize_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
164 {
165    Evas_Coord w, h;
166    Evas_Object *o;
167    
168    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
169    if (!o) return;
170    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
171    evas_object_resize(o, w, h);
172 }
173
174
175
176 //-------------------------------------------------------------------------//
177
178 EAPI void
179 _elm_access_clear(Elm_Access_Info *ac)
180 {
181    Elm_Access_Item *ai;
182
183    if (!ac) return;
184    if (ac->delay_timer)
185      {
186         ecore_timer_del(ac->delay_timer);
187         ac->delay_timer = NULL;
188      }
189    EINA_LIST_FREE(ac->items, ai)
190      {
191         if (!ai->func)
192           {
193              if (ai->data) eina_stringshare_del(ai->data);
194           }
195         free(ai);
196      }
197 }
198
199 EAPI void
200 _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text)
201 {
202    Elm_Access_Item *ai = _access_add_set(ac, type);
203    if (!ai) return;
204    ai->data = eina_stringshare_add(text);
205 }
206
207 EAPI void
208 _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Content_Cb func, const void *data)
209 {
210    Elm_Access_Item *ai = _access_add_set(ac, type);
211    if (!ai) return;
212    ai->func = func;
213    ai->data = data;
214 }
215
216 EAPI char *
217 _elm_access_text_get(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
218 {
219    Elm_Access_Item *ai;
220    Eina_List *l;
221
222    if (!ac) return NULL;
223    EINA_LIST_FOREACH(ac->items, l, ai)
224      {
225         if (ai->type == type)
226           {
227              if (ai->func) return ai->func((void *)(ai->data), obj, item);
228              else if (ai->data) return strdup(ai->data);
229              return NULL;
230           }
231      }
232    return NULL;
233 }
234
235 EAPI void
236 _elm_access_read(Elm_Access_Info *ac, int type, Evas_Object *obj, Elm_Widget_Item *item)
237 {
238    char *txt = _elm_access_text_get(ac, type, obj, item);
239
240    _access_init();
241    if (mapi)
242      {
243         if (mapi->out_done_callback_set)
244            mapi->out_done_callback_set(_access_read_done, NULL);
245         if (type == ELM_ACCESS_DONE)
246           {
247              if (mapi->out_read_done) mapi->out_read_done();
248           }
249         else if (type == ELM_ACCESS_CANCEL)
250           {
251              if (mapi->out_cancel) mapi->out_cancel();
252           }
253         else
254           {
255              if (txt)
256                {
257                   if (mapi->out_read) mapi->out_read(txt);
258                   if (mapi->out_read) mapi->out_read(".\n");
259                }
260           }
261      }
262    if (txt) free(txt);
263 }
264
265 EAPI void
266 _elm_access_say(const char *txt)
267 {
268    _access_init();
269    if (mapi)
270      {
271         if (mapi->out_done_callback_set)
272            mapi->out_done_callback_set(_access_read_done, NULL);
273         if (mapi->out_cancel) mapi->out_cancel();
274         if (txt)
275           {
276              if (mapi->out_read) mapi->out_read(txt);
277              if (mapi->out_read) mapi->out_read(".\n");
278           }
279         if (mapi->out_read_done) mapi->out_read_done();
280      }
281 }
282
283 EAPI Elm_Access_Info *
284 _elm_access_object_get(Evas_Object *obj)
285 {
286    return evas_object_data_get(obj, "_elm_access");
287 }
288
289 EAPI void
290 _elm_access_object_hilight(Evas_Object *obj)
291 {
292    Evas_Object *o;
293    Evas_Coord x, y, w, h;
294    
295    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
296    if (!o)
297      {
298         o = edje_object_add(evas_object_evas_get(obj));
299         evas_object_name_set(o, "_elm_access_disp");
300         evas_object_layer_set(o, ELM_OBJECT_LAYER_TOOLTIP);
301      }
302    else
303      {
304         Evas_Object *ptarget = evas_object_data_get(o, "_elm_access_target");
305         if (ptarget)
306           {
307              evas_object_data_del(o, "_elm_access_target");
308              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
309                                                  _access_obj_hilight_del_cb, NULL);
310              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
311                                                  _access_obj_hilight_hide_cb, NULL);
312              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
313                                                  _access_obj_hilight_move_cb, NULL);
314              evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
315                                                  _access_obj_hilight_resize_cb, NULL);
316           }
317      }
318    evas_object_data_set(o, "_elm_access_target", obj);
319    _elm_theme_object_set(obj, o, "access", "base", "default");
320    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
321                                   _access_obj_hilight_del_cb, NULL);
322    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
323                                   _access_obj_hilight_hide_cb, NULL);
324    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
325                                   _access_obj_hilight_move_cb, NULL);
326    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
327                                   _access_obj_hilight_resize_cb, NULL);
328    evas_object_raise(o);
329    evas_object_geometry_get(obj, &x, &y, &w, &h);
330    evas_object_move(o, x, y);
331    evas_object_resize(o, w, h);
332    evas_object_show(o);
333 }
334
335 EAPI void
336 _elm_access_object_unhilight(Evas_Object *obj)
337 {
338    Evas_Object *o, *ptarget;
339    
340    o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
341    if (!o) return;
342    ptarget = evas_object_data_get(o, "_elm_access_target");
343    if (ptarget == obj)
344      {
345         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
346                                             _access_obj_hilight_del_cb, NULL);
347         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
348                                             _access_obj_hilight_hide_cb, NULL);
349         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
350                                             _access_obj_hilight_move_cb, NULL);
351         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
352                                             _access_obj_hilight_resize_cb, NULL);
353         evas_object_del(o);
354      }
355 }
356
357 EAPI void
358 _elm_access_object_hilight_disable(Evas *e)
359 {
360    Evas_Object *o, *ptarget;
361
362    o = evas_object_name_find(e, "_elm_access_disp");
363    if (!o) return;
364    ptarget = evas_object_data_get(o, "_elm_access_target");
365    if (ptarget)
366      {
367         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_DEL,
368                                             _access_obj_hilight_del_cb, NULL);
369         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_HIDE,
370                                             _access_obj_hilight_hide_cb, NULL);
371         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_MOVE,
372                                             _access_obj_hilight_move_cb, NULL);
373         evas_object_event_callback_del_full(ptarget, EVAS_CALLBACK_RESIZE,
374                                             _access_obj_hilight_resize_cb, NULL);
375      }
376    evas_object_del(o);
377 }
378
379 EAPI void
380 _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj)
381 {
382    Elm_Access_Info *ac;
383
384    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_IN,
385                                   _access_obj_mouse_in_cb, obj);
386    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_MOUSE_OUT,
387                                   _access_obj_mouse_out_cb, obj);
388    evas_object_event_callback_add(hoverobj, EVAS_CALLBACK_DEL,
389                                   _access_obj_del_cb, obj);
390    ac = calloc(1, sizeof(Elm_Access_Info));
391    evas_object_data_set(obj, "_elm_access", ac);
392 }
393
394 static void
395 _access_2nd_click_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
396 {
397    Ecore_Timer *t;
398
399    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
400                                        _access_2nd_click_del_cb, NULL);
401    t = evas_object_data_get(obj, "_elm_2nd_timeout");
402    if (t)
403      {
404         ecore_timer_del(t);
405         evas_object_data_del(obj, "_elm_2nd_timeout");
406      }
407 }
408
409 static Eina_Bool
410 _access_2nd_click_timeout_cb(void *data)
411 {
412    evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL,
413                                        _access_2nd_click_del_cb, NULL);
414    evas_object_data_del(data, "_elm_2nd_timeout");
415    return EINA_FALSE;
416 }
417
418 EAPI Eina_Bool
419 _elm_access_2nd_click_timeout(Evas_Object *obj)
420 {
421    Ecore_Timer *t;
422
423    t = evas_object_data_get(obj, "_elm_2nd_timeout");
424    if (t)
425      {
426         ecore_timer_del(t);
427         evas_object_data_del(obj, "_elm_2nd_timeout");
428         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
429                                             _access_2nd_click_del_cb, NULL);
430         return EINA_TRUE;
431      }
432    t = ecore_timer_add(0.3, _access_2nd_click_timeout_cb, obj);
433    evas_object_data_set(obj, "_elm_2nd_timeout", t);
434    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
435                                   _access_2nd_click_del_cb, NULL);
436    return EINA_FALSE;
437 }
438
439 // XXX special version for items
440 //EAPI void
441 //_elm_access_item_hover_register(Elm_Widget_Item *item, Evas_Object *hoverobj)
442 //{
443 //}