1 #include "e.h"
2 
3 #define SMART_NAME     "e_widget"
4 #define API_ENTRY      E_Smart_Data * sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), SMART_NAME)))
5 #define INTERNAL_ENTRY E_Smart_Data * sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
6 typedef struct _E_Smart_Data E_Smart_Data;
7 
8 struct _E_Smart_Data
9 {
10    Evas_Object  *parent_obj;
11    Evas_Coord    x, y, w, h, minw, minh;
12    Eina_List    *subobjs;
13    Evas_Object  *resize_obj;
14    void          (*del_func)(Evas_Object *obj);
15    void          (*focus_func)(Evas_Object *obj);
16    void          (*activate_func)(Evas_Object *obj);
17    void          (*disable_func)(Evas_Object *obj);
18    void          (*on_focus_func)(void *data, Evas_Object *obj);
19    void         *on_focus_data;
20    void          (*on_change_func)(void *data, Evas_Object *obj);
21    void         *on_change_data;
22    void          (*on_disable_func)(void *data, Evas_Object *obj);
23    void         *on_disable_data;
24    void         *data;
25    unsigned char can_focus E_BITFIELD;
26    unsigned char child_can_focus E_BITFIELD;
27    unsigned char focused E_BITFIELD;
28    unsigned char disabled E_BITFIELD;
29 };
30 
31 /* local subsystem functions */
32 static void _e_smart_reconfigure(E_Smart_Data *sd);
33 static void _e_smart_add(Evas_Object *obj);
34 static void _e_smart_del(Evas_Object *obj);
35 static void _e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
36 static void _e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
37 static void _e_smart_show(Evas_Object *obj);
38 static void _e_smart_hide(Evas_Object *obj);
39 static void _e_smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
40 static void _e_smart_clip_set(Evas_Object *obj, Evas_Object *clip);
41 static void _e_smart_clip_unset(Evas_Object *obj);
42 static void _e_smart_init(void);
43 
44 static void
_e_widget_hint(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)45 _e_widget_hint(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
46 {
47    int w, h;
48 
49    evas_object_size_hint_min_get(obj, &w, &h);
50    e_widget_size_min_set(data, w, h);
51 }
52 
53 /* local subsystem globals */
54 static Evas_Smart *_e_smart = NULL;
55 
56 /* externally accessible functions */
57 E_API Evas_Object *
e_widget_add(Evas * evas)58 e_widget_add(Evas *evas)
59 {
60    _e_smart_init();
61    return evas_object_smart_add(evas, _e_smart);
62 }
63 
64 E_API void
e_widget_del_hook_set(Evas_Object * obj,void (* func)(Evas_Object * obj))65 e_widget_del_hook_set(Evas_Object *obj, void (*func)(Evas_Object *obj))
66 {
67    API_ENTRY return;
68    sd->del_func = func;
69 }
70 
71 E_API void
e_widget_focus_hook_set(Evas_Object * obj,void (* func)(Evas_Object * obj))72 e_widget_focus_hook_set(Evas_Object *obj, void (*func)(Evas_Object *obj))
73 {
74    API_ENTRY return;
75    sd->focus_func = func;
76 }
77 
78 E_API void
e_widget_activate_hook_set(Evas_Object * obj,void (* func)(Evas_Object * obj))79 e_widget_activate_hook_set(Evas_Object *obj, void (*func)(Evas_Object *obj))
80 {
81    API_ENTRY return;
82    sd->activate_func = func;
83 }
84 
85 E_API void
e_widget_disable_hook_set(Evas_Object * obj,void (* func)(Evas_Object * obj))86 e_widget_disable_hook_set(Evas_Object *obj, void (*func)(Evas_Object *obj))
87 {
88    API_ENTRY return;
89    sd->disable_func = func;
90 }
91 
92 E_API void
e_widget_on_focus_hook_set(Evas_Object * obj,void (* func)(void * data,Evas_Object * obj),void * data)93 e_widget_on_focus_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data)
94 {
95    API_ENTRY return;
96    sd->on_focus_func = func;
97    sd->on_focus_data = data;
98 }
99 
100 E_API void
e_widget_on_change_hook_set(Evas_Object * obj,void (* func)(void * data,Evas_Object * obj),void * data)101 e_widget_on_change_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data)
102 {
103    API_ENTRY return;
104    sd->on_change_func = func;
105    sd->on_change_data = data;
106 }
107 
108 E_API void
e_widget_on_disable_hook_set(Evas_Object * obj,void (* func)(void * data,Evas_Object * obj),void * data)109 e_widget_on_disable_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data)
110 {
111    API_ENTRY return;
112    sd->on_disable_func = func;
113    sd->on_disable_data = data;
114 }
115 
116 E_API void
e_widget_data_set(Evas_Object * obj,void * data)117 e_widget_data_set(Evas_Object *obj, void *data)
118 {
119    API_ENTRY return;
120    sd->data = data;
121 }
122 
123 E_API void *
e_widget_data_get(Evas_Object * obj)124 e_widget_data_get(Evas_Object *obj)
125 {
126    API_ENTRY return NULL;
127    return sd->data;
128 }
129 
130 E_API void
e_widget_size_min_set(Evas_Object * obj,Evas_Coord minw,Evas_Coord minh)131 e_widget_size_min_set(Evas_Object *obj, Evas_Coord minw, Evas_Coord minh)
132 {
133    evas_object_size_hint_min_set(obj, minw, minh);
134 }
135 
136 E_API void
e_widget_size_min_get(Evas_Object * obj,Evas_Coord * minw,Evas_Coord * minh)137 e_widget_size_min_get(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
138 {
139    evas_object_size_hint_min_get(obj, minw, minh);
140 }
141 
142 static void
_sub_obj_del(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)143 _sub_obj_del(void *data,
144              Evas *e EINA_UNUSED,
145              Evas_Object *obj,
146              void *event_info EINA_UNUSED)
147 {
148    E_Smart_Data *sd = data;
149 
150    sd->subobjs = eina_list_remove(sd->subobjs, obj);
151    evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _sub_obj_del);
152 }
153 
154 E_API void
e_widget_sub_object_add(Evas_Object * obj,Evas_Object * sobj)155 e_widget_sub_object_add(Evas_Object *obj, Evas_Object *sobj)
156 {
157    API_ENTRY return;
158 
159    if (eina_list_data_find(sd->subobjs, sobj)) return;
160 
161    sd->subobjs = eina_list_append(sd->subobjs, sobj);
162    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
163    if (!sd->child_can_focus)
164      {
165         if (e_widget_can_focus_get(sobj)) sd->child_can_focus = 1;
166      }
167    if (!evas_object_smart_parent_get(sobj))
168      evas_object_smart_member_add(sobj, obj);
169    if (strcmp(evas_object_type_get(sobj), SMART_NAME)) return;
170 
171    sd = evas_object_smart_data_get(sobj);
172    if (sd)
173      {
174         if (sd->parent_obj) e_widget_sub_object_del(sd->parent_obj, sobj);
175         sd->parent_obj = obj;
176      }
177    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
178 }
179 
180 E_API void
e_widget_sub_object_del(Evas_Object * obj,Evas_Object * sobj)181 e_widget_sub_object_del(Evas_Object *obj, Evas_Object *sobj)
182 {
183    API_ENTRY return;
184    if (evas_object_smart_parent_get(sobj) == obj)
185      evas_object_smart_member_del(sobj);
186    evas_object_event_callback_del(sobj, EVAS_CALLBACK_DEL, _sub_obj_del);
187    sd->subobjs = eina_list_remove(sd->subobjs, sobj);
188    if (!sd->child_can_focus)
189      {
190         if (e_widget_can_focus_get(sobj)) sd->child_can_focus = 0;
191      }
192 }
193 
194 E_API void
e_widget_resize_object_set(Evas_Object * obj,Evas_Object * sobj)195 e_widget_resize_object_set(Evas_Object *obj, Evas_Object *sobj)
196 {
197    int w, h;
198    API_ENTRY return;
199    if (sd->resize_obj) evas_object_smart_member_del(sd->resize_obj);
200    sd->resize_obj = sobj;
201    evas_object_event_callback_add(sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _e_widget_hint, obj);
202    evas_object_smart_member_add(sobj, obj);
203    _e_smart_reconfigure(sd);
204    evas_object_size_hint_min_get(obj, &w, &h);
205    if ((w > 0) || (h > 0)) return; //already set
206    evas_object_size_hint_min_get(sobj, &w, &h);
207    evas_object_size_hint_min_set(obj, w, h);
208 }
209 
210 E_API void
e_widget_can_focus_set(Evas_Object * obj,int can_focus)211 e_widget_can_focus_set(Evas_Object *obj, int can_focus)
212 {
213    API_ENTRY return;
214    sd->can_focus = can_focus;
215 }
216 
217 E_API int
e_widget_can_focus_get(Evas_Object * obj)218 e_widget_can_focus_get(Evas_Object *obj)
219 {
220    API_ENTRY return 0;
221    if (sd->disabled) return 0;
222    if (sd->can_focus) return 1;
223    if (sd->child_can_focus) return 1;
224    return 0;
225 }
226 
227 E_API int
e_widget_focus_get(Evas_Object * obj)228 e_widget_focus_get(Evas_Object *obj)
229 {
230    API_ENTRY return 0;
231    return sd->focused;
232 }
233 
234 E_API Evas_Object *
e_widget_focused_object_get(Evas_Object * obj)235 e_widget_focused_object_get(Evas_Object *obj)
236 {
237    Eina_List *l = NULL;
238    Evas_Object *sobj = NULL;
239 
240    API_ENTRY return NULL;
241    if (!sd->focused) return NULL;
242    EINA_LIST_FOREACH(sd->subobjs, l, sobj)
243      {
244         sobj = e_widget_focused_object_get(sobj);
245         if (sobj) return sobj;
246      }
247    return obj;
248 }
249 
250 E_API int
e_widget_focus_jump(Evas_Object * obj,int forward)251 e_widget_focus_jump(Evas_Object *obj, int forward)
252 {
253    API_ENTRY return 0;
254    if (!e_widget_can_focus_get(obj)) return 0;
255 
256    /* if it has a focus func its an end-point widget like a button */
257    if (sd->focus_func)
258      {
259         if (!sd->focused) sd->focused = 1;
260         else sd->focused = 0;
261         sd->focus_func(obj);
262         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
263         return sd->focused;
264      }
265    /* its some container */
266    else
267      {
268         Eina_List *l = NULL;
269         Evas_Object *sobj = NULL;
270         int focus_next = 0;
271 
272         if ((!sd->disabled) && (!sd->focused))
273           {
274              e_widget_focus_set(obj, forward);
275              sd->focused = 1;
276              if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
277              return 1;
278           }
279         else
280           {
281              if (forward)
282                {
283                   EINA_LIST_FOREACH(sd->subobjs, l, sobj)
284                     {
285                        if (!e_widget_can_focus_get(sobj)) continue;
286                        if (focus_next)
287                          {
288                             /* the previous focused item was unfocused - so focus
289                              * the next one (that can be focused) */
290                             if (e_widget_focus_jump(sobj, forward))
291                               return 1;
292                             break;
293                          }
294                        else
295                          {
296                             if (e_widget_focus_get(sobj))
297                               {
298                                  /* jump to the next focused item or focus this item */
299                                  if (e_widget_focus_jump(sobj, forward))
300                                    return 1;
301                                  /* it returned 0 - it got to the last item and is past it */
302                                  focus_next = 1;
303                               }
304                          }
305                     }
306                }
307              else
308                {
309                   EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, sobj)
310                     {
311                        if (e_widget_can_focus_get(sobj))
312                          {
313                             if ((focus_next) &&
314                                 (!e_widget_disabled_get(sobj)))
315                               {
316                                  /* the previous focused item was unfocused - so focus
317                                   * the next one (that can be focused) */
318                                  if (e_widget_focus_jump(sobj, forward))
319                                    return 1;
320                                  else break;
321                               }
322                             else
323                               {
324                                  if (e_widget_focus_get(sobj))
325                                    {
326                                       /* jump to the next focused item or focus this item */
327                                       if (e_widget_focus_jump(sobj, forward))
328                                         return 1;
329                                       /* it returned 0 - it got to the last item and is past it */
330                                       focus_next = 1;
331                                    }
332                               }
333                          }
334                     }
335                }
336           }
337      }
338    /* no next item can be focused */
339    sd->focused = 0;
340    return 0;
341 }
342 
343 E_API void
e_widget_focus_set(Evas_Object * obj,int first)344 e_widget_focus_set(Evas_Object *obj, int first)
345 {
346    API_ENTRY return;
347    if (!sd->focused)
348      {
349         sd->focused = 1;
350         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
351      }
352    if (sd->focus_func)
353      {
354         sd->focus_func(obj);
355         return;
356      }
357    else
358      {
359         Eina_List *l = NULL;
360         Evas_Object *sobj;
361 
362         if (first)
363           {
364              EINA_LIST_FOREACH(sd->subobjs, l, sobj)
365                {
366                   if ((e_widget_can_focus_get(sobj)) &&
367                       (!e_widget_disabled_get(sobj)))
368                     {
369                        e_widget_focus_set(sobj, first);
370                        break;
371                     }
372                }
373           }
374         else
375           {
376              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, sobj)
377                {
378                   if ((e_widget_can_focus_get(sobj)) &&
379                       (!e_widget_disabled_get(sobj)))
380                     {
381                        e_widget_focus_set(sobj, first);
382                        break;
383                     }
384                }
385           }
386      }
387 }
388 
389 E_API Evas_Object *
e_widget_parent_get(Evas_Object * obj)390 e_widget_parent_get(Evas_Object *obj)
391 {
392    API_ENTRY return NULL;
393    return sd->parent_obj;
394 }
395 
396 E_API void
e_widget_focused_object_clear(Evas_Object * obj)397 e_widget_focused_object_clear(Evas_Object *obj)
398 {
399    Eina_List *l = NULL;
400    Evas_Object *sobj = NULL;
401 
402    API_ENTRY return;
403    if (!sd->focused) return;
404    sd->focused = 0;
405    EINA_LIST_FOREACH(sd->subobjs, l, sobj)
406      {
407         if (e_widget_focus_get(sobj))
408           {
409              e_widget_focused_object_clear(sobj);
410              break;
411           }
412      }
413    if (sd->focus_func) sd->focus_func(obj);
414 }
415 
416 E_API void
e_widget_focus_steal(Evas_Object * obj)417 e_widget_focus_steal(Evas_Object *obj)
418 {
419    Evas_Object *parent = NULL, *o = NULL;
420 
421    API_ENTRY return;
422    if ((sd->focused) || (sd->disabled) || (!sd->can_focus)) return;
423    parent = obj;
424    for (;; )
425      {
426         o = e_widget_parent_get(parent);
427         if (!o) break;
428         parent = o;
429      }
430    e_widget_focused_object_clear(parent);
431    parent = obj;
432    for (;; )
433      {
434         sd = evas_object_smart_data_get(parent);
435         sd->focused = 1;
436         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, parent);
437         o = e_widget_parent_get(parent);
438         if (!o) break;
439         parent = o;
440      }
441    sd = evas_object_smart_data_get(obj);
442    if (sd->focus_func) sd->focus_func(obj);
443 }
444 
445 E_API void
e_widget_activate(Evas_Object * obj)446 e_widget_activate(Evas_Object *obj)
447 {
448    API_ENTRY return;
449    e_widget_change(obj);
450    if (sd->activate_func) sd->activate_func(obj);
451 }
452 
453 E_API void
e_widget_change(Evas_Object * obj)454 e_widget_change(Evas_Object *obj)
455 {
456    API_ENTRY return;
457    if (sd->parent_obj) e_widget_change(sd->parent_obj);
458    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
459 }
460 
461 E_API void
e_widget_disabled_set(Evas_Object * obj,int disabled)462 e_widget_disabled_set(Evas_Object *obj, int disabled)
463 {
464    API_ENTRY return;
465    if (sd->disabled == !!disabled) return;
466    sd->disabled = !!disabled;
467    if (sd->focused && sd->disabled)
468      {
469         Evas_Object *o = NULL, *parent = NULL;
470 
471         parent = obj;
472         for (;; )
473           {
474              o = e_widget_parent_get(parent);
475              if (!o) break;
476              parent = o;
477           }
478         e_widget_focus_jump(parent, 1);
479         if (sd->focused)
480           {
481              sd->focused = 0;
482              if (sd->focus_func) sd->focus_func(obj);
483           }
484      }
485    if (sd->disable_func) sd->disable_func(obj);
486    if (sd->on_disable_func) sd->on_disable_func(sd->on_disable_data, obj);
487 }
488 
489 E_API int
e_widget_disabled_get(Evas_Object * obj)490 e_widget_disabled_get(Evas_Object *obj)
491 {
492    API_ENTRY return 0;
493    return sd->disabled;
494 }
495 
496 E_API E_Pointer *
e_widget_pointer_get(Evas_Object * obj)497 e_widget_pointer_get(Evas_Object *obj)
498 {
499    Evas_Object *win = NULL;
500 
501    API_ENTRY return NULL;
502    win = e_win_evas_object_win_get(obj);
503    if (win) return e_win_pointer_get(win);
504    return NULL;
505 }
506 
507 E_API void
e_widget_size_min_resize(Evas_Object * obj)508 e_widget_size_min_resize(Evas_Object *obj)
509 {
510    Evas_Coord minw, minh;
511    evas_object_size_hint_min_get(obj, &minw, &minh);
512    evas_object_resize(obj, minw, minh);
513 }
514 
515 /* local subsystem functions */
516 static void
_e_smart_reconfigure(E_Smart_Data * sd)517 _e_smart_reconfigure(E_Smart_Data *sd)
518 {
519    if (sd->resize_obj)
520      {
521         evas_object_move(sd->resize_obj, sd->x, sd->y);
522         evas_object_resize(sd->resize_obj, sd->w, sd->h);
523      }
524 }
525 
526 static void
_e_smart_add(Evas_Object * obj)527 _e_smart_add(Evas_Object *obj)
528 {
529    E_Smart_Data *sd = NULL;
530 
531    sd = calloc(1, sizeof(E_Smart_Data));
532    if (!sd) return;
533    sd->x = 0;
534    sd->y = 0;
535    sd->w = 0;
536    sd->h = 0;
537    sd->can_focus = 1;
538    evas_object_smart_data_set(obj, sd);
539 }
540 
541 static void
_e_smart_del(Evas_Object * obj)542 _e_smart_del(Evas_Object *obj)
543 {
544    INTERNAL_ENTRY;
545 
546    if (sd->del_func) sd->del_func(obj);
547    while (sd->subobjs)
548      {
549         Evas_Object *sobj = sd->subobjs->data;
550         /* DO NOT MACRO THIS!
551          * list gets reshuffled during object delete callback chain
552          * and breaks the world.
553          * BORKER CERTIFICATION: GOLD
554          * -discomfitor, 7/4/2012
555          */
556         evas_object_event_callback_del(sobj, EVAS_CALLBACK_DEL, _sub_obj_del);
557         sd->subobjs = eina_list_remove_list(sd->subobjs, sd->subobjs);
558         evas_object_del(sobj);
559      }
560    free(sd);
561 }
562 
563 static void
_e_smart_move(Evas_Object * obj,Evas_Coord x,Evas_Coord y)564 _e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
565 {
566    INTERNAL_ENTRY;
567    sd->x = x;
568    sd->y = y;
569    _e_smart_reconfigure(sd);
570 }
571 
572 static void
_e_smart_resize(Evas_Object * obj,Evas_Coord w,Evas_Coord h)573 _e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
574 {
575    INTERNAL_ENTRY;
576    sd->w = w;
577    sd->h = h;
578    _e_smart_reconfigure(sd);
579 }
580 
581 static void
_e_smart_show(Evas_Object * obj)582 _e_smart_show(Evas_Object *obj)
583 {
584    INTERNAL_ENTRY;
585    if (sd->resize_obj)
586      evas_object_show(sd->resize_obj);
587 }
588 
589 static void
_e_smart_hide(Evas_Object * obj)590 _e_smart_hide(Evas_Object *obj)
591 {
592    INTERNAL_ENTRY;
593    if (sd->resize_obj)
594      evas_object_hide(sd->resize_obj);
595 }
596 
597 static void
_e_smart_color_set(Evas_Object * obj,int r,int g,int b,int a)598 _e_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
599 {
600    INTERNAL_ENTRY;
601    if (sd->resize_obj)
602      evas_object_color_set(sd->resize_obj, r, g, b, a);
603 }
604 
605 static void
_e_smart_clip_set(Evas_Object * obj,Evas_Object * clip)606 _e_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
607 {
608    INTERNAL_ENTRY;
609    if (sd->resize_obj)
610      evas_object_clip_set(sd->resize_obj, clip);
611 }
612 
613 static void
_e_smart_clip_unset(Evas_Object * obj)614 _e_smart_clip_unset(Evas_Object *obj)
615 {
616    INTERNAL_ENTRY;
617    if (sd->resize_obj)
618      evas_object_clip_unset(sd->resize_obj);
619 }
620 
621 /* never need to touch this */
622 
623 static void
_e_smart_init(void)624 _e_smart_init(void)
625 {
626    if (_e_smart) return;
627    {
628       static const Evas_Smart_Class sc =
629       {
630          SMART_NAME,
631          EVAS_SMART_CLASS_VERSION,
632          _e_smart_add,
633          _e_smart_del,
634          _e_smart_move,
635          _e_smart_resize,
636          _e_smart_show,
637          _e_smart_hide,
638          _e_smart_color_set,
639          _e_smart_clip_set,
640          _e_smart_clip_unset,
641          NULL,
642          NULL,
643          NULL,
644          NULL,
645          NULL,
646          NULL,
647          NULL
648       };
649       _e_smart = evas_smart_class_new(&sc);
650    }
651 }
652 
653