svn update: 49550 (latest:49550)
[framework/uifw/elementary.git] / src / lib / elm_widget.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char SMART_NAME[] = "elm_widget";
5
6 #define API_ENTRY \
7    Smart_Data *sd = evas_object_smart_data_get(obj); \
8    if ((!obj) || (!sd) || (!_elm_widget_is(obj)))
9 #define INTERNAL_ENTRY \
10    Smart_Data *sd = evas_object_smart_data_get(obj); \
11    if (!sd) return;
12
13 typedef struct _Smart_Data Smart_Data;
14
15 struct _Smart_Data
16 {
17    Evas_Object   *obj;
18    const char    *type;
19    Evas_Object   *parent_obj;
20    Evas_Coord     x, y, w, h;
21    Eina_List     *subobjs;
22    Evas_Object   *resize_obj;
23    Evas_Object   *hover_obj;
24    void         (*del_func) (Evas_Object *obj);
25    void         (*del_pre_func) (Evas_Object *obj);
26    void         (*focus_func) (Evas_Object *obj);
27    void         (*activate_func) (Evas_Object *obj);
28    void         (*disable_func) (Evas_Object *obj);
29    void         (*theme_func) (Evas_Object *obj);
30    void         (*changed_func) (Evas_Object *obj);
31    void         (*on_focus_func) (void *data, Evas_Object *obj);
32    void          *on_focus_data;
33    void         (*on_change_func) (void *data, Evas_Object *obj);
34    void          *on_change_data;
35    void         (*on_show_region_func) (void *data, Evas_Object *obj);
36    void          *on_show_region_data;
37    void          *data;
38    Evas_Coord     rx, ry, rw, rh;
39    int            scroll_hold;
40    int            scroll_freeze;
41    double         scale;
42    Elm_Theme     *theme;
43    const char    *style;
44    
45    int            child_drag_x_locked;
46    int            child_drag_y_locked;
47    Eina_Bool      drag_x_locked : 1;
48    Eina_Bool      drag_y_locked : 1;
49    
50    Eina_Bool      can_focus : 1;
51    Eina_Bool      child_can_focus : 1;
52    Eina_Bool      focused : 1;
53    Eina_Bool      disabled : 1;
54 };
55
56 /* local subsystem functions */
57 static void _smart_reconfigure(Smart_Data *sd);
58 static void _smart_add(Evas_Object *obj);
59 static void _smart_del(Evas_Object *obj);
60 static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
61 static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
62 static void _smart_show(Evas_Object *obj);
63 static void _smart_hide(Evas_Object *obj);
64 static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
65 static void _smart_clip_set(Evas_Object *obj, Evas_Object * clip);
66 static void _smart_clip_unset(Evas_Object *obj);
67 static void _smart_calculate(Evas_Object *obj);
68 static void _smart_init(void);
69 static inline Eina_Bool _elm_widget_is(const Evas_Object *obj);
70
71 /* local subsystem globals */
72 static Evas_Smart *_e_smart = NULL;
73
74 static void
75 _sub_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
76 {
77    Smart_Data *sd = data;
78
79    if (obj == sd->resize_obj)
80      sd->resize_obj = NULL;
81    else if (obj == sd->hover_obj)
82      sd->hover_obj = NULL;
83    else
84      sd->subobjs = eina_list_remove(sd->subobjs, obj);
85    evas_object_smart_callback_call(sd->obj, "sub-object-del", obj);
86 }
87
88 static void
89 _sub_obj_mouse_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
90 {
91    Evas_Object *o = obj;
92    do 
93      {
94         if (_elm_widget_is(o)) break;
95         o = evas_object_smart_parent_get(o);
96      }
97    while (o);
98    if (!o) return;
99    if (!elm_widget_can_focus_get(o)) return;
100    elm_widget_focus_steal(o);
101 }
102
103 EAPI Evas_Object *
104 elm_widget_add(Evas *evas)
105 {
106    _smart_init();
107    return evas_object_smart_add(evas, _e_smart);
108 }
109
110 EAPI void
111 elm_widget_del_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
112 {
113    API_ENTRY return;
114    sd->del_func = func;
115 }
116
117 EAPI void
118 elm_widget_del_pre_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
119 {
120    API_ENTRY return;
121    sd->del_pre_func = func;
122 }
123
124 EAPI void
125 elm_widget_focus_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
126 {
127    API_ENTRY return;
128    sd->focus_func = func;
129 }
130
131 EAPI void
132 elm_widget_activate_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
133 {
134    API_ENTRY return;
135    sd->activate_func = func;
136 }
137
138 EAPI void
139 elm_widget_disable_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
140 {
141    API_ENTRY return;
142    sd->disable_func = func;
143 }
144
145 EAPI void
146 elm_widget_theme_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
147 {
148    API_ENTRY return;
149    sd->theme_func = func;
150 }
151
152 EAPI void
153 elm_widget_changed_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
154 {
155    API_ENTRY return;
156    sd->changed_func = func;
157 }
158
159 EAPI void
160 elm_widget_theme(Evas_Object *obj)
161 {
162    const Eina_List *l;
163    Evas_Object *child;
164
165    API_ENTRY return;
166    EINA_LIST_FOREACH(sd->subobjs, l, child)
167      elm_widget_theme(child);
168    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
169    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
170    if (sd->theme_func) sd->theme_func(obj);
171 }
172
173 EAPI void
174 elm_widget_on_focus_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
175 {
176    API_ENTRY return;
177    sd->on_focus_func = func;
178    sd->on_focus_data = data;
179 }
180
181 EAPI void
182 elm_widget_on_change_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
183 {
184    API_ENTRY return;
185    sd->on_change_func = func;
186    sd->on_change_data = data;
187 }
188
189 EAPI void
190 elm_widget_on_show_region_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
191 {
192    API_ENTRY return;
193    sd->on_show_region_func = func;
194    sd->on_show_region_data = data;
195 }
196
197 EAPI void
198 elm_widget_data_set(Evas_Object *obj, void *data)
199 {
200    API_ENTRY return;
201    sd->data = data;
202 }
203
204 EAPI void *
205 elm_widget_data_get(const Evas_Object *obj)
206 {
207    API_ENTRY return NULL;
208    return sd->data;
209 }
210
211 EAPI void
212 elm_widget_sub_object_add(Evas_Object *obj, Evas_Object *sobj)
213 {
214    API_ENTRY return;
215    double scale, pscale = elm_widget_scale_get(sobj);
216    Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
217
218    sd->subobjs = eina_list_append(sd->subobjs, sobj);
219    if (!sd->child_can_focus)
220      {
221         if (elm_widget_can_focus_get(sobj)) sd->child_can_focus = 1;
222      }
223    if (_elm_widget_is(sobj))
224      {
225         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
226         if (sd2)
227           {
228              if (sd2->parent_obj)
229                elm_widget_sub_object_del(sd2->parent_obj, sobj);
230              sd2->parent_obj = obj;
231           }
232      }
233    evas_object_data_set(sobj, "elm-parent", obj);
234    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
235    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
236    scale = elm_widget_scale_get(sobj);
237    th = elm_widget_theme_get(sobj);
238    if ((scale != pscale) || (th != pth)) elm_widget_theme(sobj);
239 }
240
241 EAPI void
242 elm_widget_sub_object_del(Evas_Object *obj, Evas_Object *sobj)
243 {
244    Evas_Object *sobj_parent;
245    API_ENTRY return;
246    if (!sobj) return;
247
248    sobj_parent = evas_object_data_del(sobj, "elm-parent");
249    if (sobj_parent != obj)
250      {
251         static int abort_on_warn = -1;
252         ERR("removing sub object %p from parent %p, "
253             "but elm-parent is different %p!",
254             sobj, obj, sobj_parent);
255         if (EINA_UNLIKELY(abort_on_warn == -1))
256           {
257              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
258              else abort_on_warn = 0;
259           }
260         if (abort_on_warn == 1) abort();
261      }
262    sd->subobjs = eina_list_remove(sd->subobjs, sobj);
263    if (!sd->child_can_focus)
264      {
265         if (elm_widget_can_focus_get(sobj)) sd->child_can_focus = 0;
266      }
267    if (_elm_widget_is(sobj))
268      {
269         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
270         if (sd2) sd2->parent_obj = NULL;
271      }
272    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
273    evas_object_smart_callback_call(obj, "sub-object-del", sobj);
274 }
275
276 EAPI void
277 elm_widget_resize_object_set(Evas_Object *obj, Evas_Object *sobj)
278 {
279    API_ENTRY return;
280    if (sd->resize_obj)
281      {
282         evas_object_data_del(sd->resize_obj, "elm-parent");
283         if (_elm_widget_is(sd->resize_obj))
284           {
285              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
286              if (sd2) sd2->parent_obj = NULL;
287           }
288         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_DEL,
289            _sub_obj_del, sd);
290         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_DOWN,
291            _sub_obj_mouse_down, sd);
292         evas_object_smart_member_del(sd->resize_obj);
293      }
294    sd->resize_obj = sobj;
295    if (sd->resize_obj)
296      {
297         if (_elm_widget_is(sd->resize_obj))
298           {
299              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
300              if (sd2) sd2->parent_obj = obj;
301           }
302         evas_object_clip_set(sobj, evas_object_clip_get(obj));
303         evas_object_smart_member_add(sobj, obj);
304         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
305         evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_DOWN,
306                                        _sub_obj_mouse_down, sd);
307         _smart_reconfigure(sd);
308         evas_object_data_set(sobj, "elm-parent", obj);
309         evas_object_smart_callback_call(obj, "sub-object-add", sobj);
310      }
311 }
312
313 EAPI void
314 elm_widget_hover_object_set(Evas_Object *obj, Evas_Object *sobj)
315 {
316    API_ENTRY return;
317    if (sd->hover_obj)
318      {
319         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
320            _sub_obj_del, sd);
321      }
322    sd->hover_obj = sobj;
323    if (sd->hover_obj)
324      {
325         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
326         _smart_reconfigure(sd);
327      }
328 }
329
330 EAPI void
331 elm_widget_can_focus_set(Evas_Object *obj, int can_focus)
332 {
333    API_ENTRY return;
334    sd->can_focus = can_focus;
335 }
336
337 EAPI int
338 elm_widget_can_focus_get(const Evas_Object *obj)
339 {
340    API_ENTRY return 0;
341    if (sd->can_focus) return 1;
342    if (sd->child_can_focus) return 1;
343    return 0;
344 }
345
346 EAPI int
347 elm_widget_focus_get(const Evas_Object *obj)
348 {
349    API_ENTRY return 0;
350    return sd->focused;
351 }
352
353 EAPI Evas_Object *
354 elm_widget_focused_object_get(const Evas_Object *obj)
355 {
356    const Evas_Object *subobj;
357    const Eina_List *l;
358    API_ENTRY return NULL;
359
360    if (!sd->focused) return NULL;
361    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
362      {
363         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
364         if (fobj) return fobj;
365      }
366    return (Evas_Object *)obj;
367 }
368
369 EAPI Evas_Object *
370 elm_widget_top_get(const Evas_Object *obj)
371 {
372 #if 1 // strict way  
373    API_ENTRY return NULL;
374    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
375    return (Evas_Object *)obj;
376 #else // loose way
377    Smart_Data *sd = evas_object_smart_data_get(obj);
378    Evas_Object *par;
379    
380    if (!obj) return NULL;
381    if ((sd) && _elm_widget_is(obj))
382      {
383         if ((sd->type) && (!strcmp(sd->type, "win"))) 
384           return (Evas_Object *)obj;
385         if (sd->parent_obj)
386           return elm_widget_top_get(sd->parent_obj);
387      }
388    par = evas_object_smart_parent_get(obj);
389    if (!par) return (Evas_Object *)obj;
390    return elm_widget_top_get(par);
391 #endif   
392 }
393
394 EAPI Eina_Bool
395 elm_widget_is(const Evas_Object *obj)
396 {
397    return _elm_widget_is(obj);
398 }
399
400 EAPI Evas_Object *
401 elm_widget_parent_widget_get(const Evas_Object *obj)
402 {
403    Evas_Object *parent;
404
405    if (_elm_widget_is(obj))
406      {
407         Smart_Data *sd = evas_object_smart_data_get(obj);
408         if (!sd) return NULL;
409         parent = sd->parent_obj;
410      }
411    else
412      {
413         parent = evas_object_data_get(obj, "elm-parent");
414         if (!parent)
415           parent = evas_object_smart_data_get(obj);
416      }
417
418    while (parent)
419      {
420         Evas_Object *elm_parent;
421         if (_elm_widget_is(parent)) break;
422         elm_parent = evas_object_data_get(parent, "elm-parent");
423         if (elm_parent)
424           parent = elm_parent;
425         else
426           parent = evas_object_smart_parent_get(parent);
427      }
428    return parent;
429 }
430
431 EAPI int
432 elm_widget_focus_jump(Evas_Object *obj, int forward)
433 {
434    API_ENTRY return 0;
435    if (!elm_widget_can_focus_get(obj)) return 0;
436
437    /* if it has a focus func its an end-point widget like a button */
438    if (sd->focus_func)
439      {
440         if (!sd->focused) sd->focused = 1;
441         else sd->focused = 0;
442         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
443         sd->focus_func(obj);
444         return sd->focused;
445      }
446    /* its some container */
447    else
448      {
449         int focus_next;
450         int noloop = 0;
451
452         focus_next = 0;
453         if (!sd->focused)
454           {
455              elm_widget_focus_set(obj, forward);
456              sd->focused = 1;
457              if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
458              return 1;
459           }
460         else
461           {
462              if (forward)
463                {
464                   if (elm_widget_can_focus_get(sd->resize_obj))
465                     {
466                        if ((focus_next) &&
467                            (!elm_widget_disabled_get(sd->resize_obj)))
468                          {
469                             /* the previous focused item was unfocused - so focus
470                              * the next one (that can be focused) */
471                             if (elm_widget_focus_jump(sd->resize_obj, forward))
472                               return 1;
473                             else noloop = 1;
474                          }
475                        else
476                          {
477                             if (elm_widget_focus_get(sd->resize_obj))
478                               {
479                                  /* jump to the next focused item or focus this item */
480                                  if (elm_widget_focus_jump(sd->resize_obj, forward))
481                                    return 1;
482                                  /* it returned 0 - it got to the last item and is past it */
483                                  focus_next = 1;
484                               }
485                          }
486                     }
487                   if (!noloop)
488                     {
489                        const Eina_List *l;
490                        Evas_Object *child;
491                        EINA_LIST_FOREACH(sd->subobjs, l, child)
492                          {
493                             if (elm_widget_can_focus_get(child))
494                               {
495                                  if ((focus_next) &&
496                                      (!elm_widget_disabled_get(child)))
497                                    {
498                                       /* the previous focused item was unfocused - so focus
499                                        * the next one (that can be focused) */
500                                       if (elm_widget_focus_jump(child, forward))
501                                         return 1;
502                                       else break;
503                                    }
504                                  else
505                                    {
506                                       if (elm_widget_focus_get(child))
507                                         {
508                                            /* jump to the next focused item or focus this item */
509                                            if (elm_widget_focus_jump(child, forward))
510                                              return 1;
511                                            /* it returned 0 - it got to the last item and is past it */
512                                            focus_next = 1;
513                                         }
514                                    }
515                               }
516                          }
517                     }
518                }
519              else
520                {
521                   const Eina_List *l;
522                   Evas_Object *child;
523
524                   EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
525                     {
526                        if (elm_widget_can_focus_get(child))
527                          {
528                             if ((focus_next) &&
529                                 (!elm_widget_disabled_get(child)))
530                               {
531                                  /* the previous focused item was unfocused - so focus
532                                   * the next one (that can be focused) */
533                                  if (elm_widget_focus_jump(child, forward))
534                                    return 1;
535                                  else break;
536                               }
537                             else
538                               {
539                                  if (elm_widget_focus_get(child))
540                                    {
541                                       /* jump to the next focused item or focus this item */
542                                       if (elm_widget_focus_jump(child, forward))
543                                         return 1;
544                                       /* it returned 0 - it got to the last item and is past it */
545                                       focus_next = 1;
546                                    }
547                               }
548                          }
549                     }
550                   if (!l)
551                     {
552                        if (elm_widget_can_focus_get(sd->resize_obj))
553                          {
554                             if ((focus_next) &&
555                                 (!elm_widget_disabled_get(sd->resize_obj)))
556                               {
557                                  /* the previous focused item was unfocused - so focus
558                                   * the next one (that can be focused) */
559                                  if (elm_widget_focus_jump(sd->resize_obj, forward))
560                                    return 1;
561                               }
562                             else
563                               {
564                                  if (elm_widget_focus_get(sd->resize_obj))
565                                    {
566                                       /* jump to the next focused item or focus this item */
567                                       if (elm_widget_focus_jump(sd->resize_obj, forward))
568                                         return 1;
569                                       /* it returned 0 - it got to the last item and is past it */
570                                       focus_next = 1;
571                                    }
572                               }
573                          }
574                     }
575                }
576           }
577      }
578    /* no next item can be focused */
579    if (sd->focused)
580      {
581         sd->focused = 0;
582         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
583      }
584    return 0;
585 }
586
587 EAPI void
588 elm_widget_focus_set(Evas_Object *obj, int first)
589 {
590    API_ENTRY return;
591    if (!sd->focused)
592      {
593         sd->focused = 1;
594         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
595      }
596    if (sd->focus_func)
597      {
598         sd->focus_func(obj);
599         return;
600      }
601    else
602      {
603         if (first)
604           {
605              if ((elm_widget_can_focus_get(sd->resize_obj)) &&
606                  (!elm_widget_disabled_get(sd->resize_obj)))
607                {
608                   elm_widget_focus_set(sd->resize_obj, first);
609                }
610              else
611                {
612                   const Eina_List *l;
613                   Evas_Object *child;
614                   EINA_LIST_FOREACH(sd->subobjs, l, child)
615                     {
616                        if ((elm_widget_can_focus_get(child)) &&
617                            (!elm_widget_disabled_get(child)))
618                          {
619                             elm_widget_focus_set(child, first);
620                             break;
621                          }
622                     }
623                }
624           }
625         else
626           {
627              const Eina_List *l;
628              Evas_Object *child;
629              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
630                {
631                   if ((elm_widget_can_focus_get(child)) &&
632                       (!elm_widget_disabled_get(child)))
633                     {
634                        elm_widget_focus_set(child, first);
635                        break;
636                     }
637                }
638              if (!l)
639                {
640                   if ((elm_widget_can_focus_get(sd->resize_obj)) &&
641                       (!elm_widget_disabled_get(sd->resize_obj)))
642                     {
643                        elm_widget_focus_set(sd->resize_obj, first);
644                     }
645                }
646           }
647      }
648 }
649
650 EAPI Evas_Object *
651 elm_widget_parent_get(const Evas_Object *obj)
652 {
653    API_ENTRY return NULL;
654    return sd->parent_obj;
655 }
656
657 EAPI void
658 elm_widget_focused_object_clear(Evas_Object *obj)
659 {
660    API_ENTRY return;
661    if (!sd->focused) return;
662    if (elm_widget_focus_get(sd->resize_obj))
663      elm_widget_focused_object_clear(sd->resize_obj);
664    else
665      {
666         const Eina_List *l;
667         Evas_Object *child;
668         EINA_LIST_FOREACH(sd->subobjs, l, child)
669           {
670              if (elm_widget_focus_get(child))
671                {
672                   elm_widget_focused_object_clear(child);
673                   break;
674                }
675           }
676      }
677    sd->focused = 0;
678    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
679    if (sd->focus_func) sd->focus_func(obj);
680 }
681
682 static void
683 _elm_widget_parent_focus(Evas_Object *obj)
684 {
685    API_ENTRY return;
686    Evas_Object *o = elm_widget_parent_get(obj);
687
688    if (sd->focused) return;
689    if (o) _elm_widget_parent_focus(o);
690    sd->focused = 1;
691    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
692    if (sd->focus_func) sd->focus_func(obj);
693 }
694
695 EAPI void
696 elm_widget_focus_steal(Evas_Object *obj)
697 {
698    Evas_Object *parent, *o;
699    API_ENTRY return;
700
701    if (sd->focused) return;
702    if (sd->disabled) return;
703    parent = obj;
704    for (;;)
705      {
706         o = elm_widget_parent_get(parent);
707         if (!o) break;
708         sd = evas_object_smart_data_get(o);
709         if (sd->focused) break;
710         parent = o;
711      }
712    if (!elm_widget_parent_get(parent))
713      elm_widget_focused_object_clear(parent);
714    else
715      {
716         parent = elm_widget_parent_get(parent);
717         sd = evas_object_smart_data_get(parent);
718         if (elm_widget_focus_get(sd->resize_obj))
719           {
720              elm_widget_focused_object_clear(sd->resize_obj);
721           }
722         else
723           {
724              const Eina_List *l;
725              Evas_Object *child;
726              EINA_LIST_FOREACH(sd->subobjs, l, child)
727                {
728                   if (elm_widget_focus_get(child))
729                     {
730                        elm_widget_focused_object_clear(child);
731                        break;
732                     }
733                }
734           }
735      }
736    _elm_widget_parent_focus(obj);
737    return;
738 }
739
740 EAPI void
741 elm_widget_activate(Evas_Object *obj)
742 {
743    API_ENTRY return;
744    elm_widget_change(obj);
745    if (sd->activate_func) sd->activate_func(obj);
746 }
747
748 EAPI void
749 elm_widget_change(Evas_Object *obj)
750 {
751    API_ENTRY return;
752    elm_widget_change(elm_widget_parent_get(obj));
753    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
754 }
755
756 EAPI void
757 elm_widget_disabled_set(Evas_Object *obj, int disabled)
758 {
759    API_ENTRY return;
760
761    if (sd->disabled == disabled) return;
762    sd->disabled = disabled;
763    if (sd->focused)
764      {
765         Evas_Object *o, *parent;
766
767         parent = obj;
768         for (;;)
769           {
770              o = elm_widget_parent_get(parent);
771              if (!o) break;
772              parent = o;
773           }
774         elm_widget_focus_jump(parent, 1);
775      }
776    if (sd->disable_func) sd->disable_func(obj);
777 }
778
779 EAPI int
780 elm_widget_disabled_get(const Evas_Object *obj)
781 {
782    API_ENTRY return 0;
783    return sd->disabled;
784 }
785
786 EAPI void
787 elm_widget_show_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
788 {
789    API_ENTRY return;
790    if ((x == sd->rx) && (y == sd->ry) && (w == sd->rw) && (h == sd->rh)) return;
791    sd->rx = x;
792    sd->ry = y;
793    sd->rw = w;
794    sd->rh = h;
795    if (sd->on_show_region_func)
796      sd->on_show_region_func(sd->on_show_region_data, obj);
797 }
798
799 EAPI void
800 elm_widget_show_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
801 {
802    API_ENTRY return;
803    if (x) *x = sd->rx;
804    if (y) *y = sd->ry;
805    if (w) *w = sd->rw;
806    if (h) *h = sd->rh;
807 }
808
809 EAPI void
810 elm_widget_scroll_hold_push(Evas_Object *obj)
811 {
812    API_ENTRY return;
813    sd->scroll_hold++;
814    if (sd->scroll_hold == 1)
815      evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
816    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
817    // FIXME: on delete/reparent hold pop
818 }
819
820 EAPI void
821 elm_widget_scroll_hold_pop(Evas_Object *obj)
822 {
823    API_ENTRY return;
824    sd->scroll_hold--;
825    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
826    if (sd->scroll_hold == 0)
827      evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
828    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
829 }
830
831 EAPI int
832 elm_widget_scroll_hold_get(const Evas_Object *obj)
833 {
834    API_ENTRY return 0;
835    return sd->scroll_hold;
836 }
837
838 EAPI void
839 elm_widget_scroll_freeze_push(Evas_Object *obj)
840 {
841    API_ENTRY return;
842    sd->scroll_freeze++;
843    if (sd->scroll_freeze == 1)
844      evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
845    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
846    // FIXME: on delete/reparent freeze pop
847 }
848
849 EAPI void
850 elm_widget_scroll_freeze_pop(Evas_Object *obj)
851 {
852    API_ENTRY return;
853    sd->scroll_freeze--;
854    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
855    if (sd->scroll_freeze == 0)
856      evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
857    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
858 }
859
860 EAPI int
861 elm_widget_scroll_freeze_get(const Evas_Object *obj)
862 {
863    API_ENTRY return 0;
864    return sd->scroll_freeze;
865 }
866
867 EAPI void
868 elm_widget_scale_set(Evas_Object *obj, double scale)
869 {
870    API_ENTRY return;
871    if (scale <= 0.0) scale = 0.0;
872    if (sd->scale != scale)
873      {
874         sd->scale = scale;
875         elm_widget_theme(obj);
876      }
877 }
878
879 EAPI double
880 elm_widget_scale_get(const Evas_Object *obj)
881 {
882    API_ENTRY return 1.0;
883    // FIXME: save walking up the tree by storingcaching parent scale
884    if (sd->scale == 0.0)
885      {
886         if (sd->parent_obj)
887           return elm_widget_scale_get(sd->parent_obj);
888         else
889           return 1.0;
890      }
891    return sd->scale;
892 }
893
894 EAPI void
895 elm_widget_theme_set(Evas_Object *obj, Elm_Theme *th)
896 {
897    API_ENTRY return;
898    if (sd->theme != th)
899      {
900         if (sd->theme) elm_theme_free(sd->theme);
901         sd->theme = th;
902         if (th) th->ref++;
903         elm_widget_theme(obj);
904      }
905 }
906
907 EAPI Elm_Theme *
908 elm_widget_theme_get(const Evas_Object *obj)
909 {
910    API_ENTRY return NULL;
911    if (!sd->theme)
912      {
913         if (sd->parent_obj)
914           return elm_widget_theme_get(sd->parent_obj);
915         else
916           return NULL;
917      }
918    return sd->theme;
919 }
920
921 EAPI void
922 elm_widget_style_set(Evas_Object *obj, const char *style)
923 {
924    API_ENTRY return;
925
926    if (eina_stringshare_replace(&sd->style, style))
927      elm_widget_theme(obj);
928 }
929
930 EAPI const char *
931 elm_widget_style_get(const Evas_Object *obj)
932 {
933    API_ENTRY return "";
934    if (sd->style) return sd->style;
935    return "default";
936 }
937
938 EAPI void
939 elm_widget_type_set(Evas_Object *obj, const char *type)
940 {
941    API_ENTRY return;
942    eina_stringshare_replace(&sd->type, type);
943 }
944
945 EAPI const char *
946 elm_widget_type_get(const Evas_Object *obj)
947 {
948    API_ENTRY return "";
949    if (sd->type) return sd->type;
950    return "";
951 }
952
953
954
955
956
957
958
959
960
961 static void
962 _propagate_x_drag_lock(Evas_Object *obj, int dir)
963 {
964    Smart_Data *sd = evas_object_smart_data_get(obj);
965    if (sd->parent_obj)
966      {
967         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
968         if (sd2)
969           {
970              sd2->child_drag_x_locked += dir;
971              _propagate_x_drag_lock(sd->parent_obj, dir);
972           }
973      }
974 }
975
976 static void
977 _propagate_y_drag_lock(Evas_Object *obj, int dir)
978 {
979    Smart_Data *sd = evas_object_smart_data_get(obj);
980    if (sd->parent_obj)
981      {
982         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
983         if (sd2)
984           {
985              sd2->child_drag_y_locked += dir;
986              _propagate_y_drag_lock(sd->parent_obj, dir);
987           }
988      }
989 }
990
991 EAPI void
992 elm_widget_drag_lock_x_set(Evas_Object *obj, Eina_Bool lock)
993 {
994    API_ENTRY return;
995    if (sd->drag_x_locked == lock) return;
996    sd->drag_x_locked = lock;
997    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
998    else _propagate_x_drag_lock(obj, -1);
999 }
1000
1001 EAPI void
1002 elm_widget_drag_lock_y_set(Evas_Object *obj, Eina_Bool lock)
1003 {
1004    API_ENTRY return;
1005    if (sd->drag_y_locked == lock) return;
1006    sd->drag_y_locked = lock;
1007    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
1008    else _propagate_y_drag_lock(obj, -1);
1009 }
1010
1011 EAPI Eina_Bool
1012 elm_widget_drag_lock_x_get(Evas_Object *obj)
1013 {
1014    API_ENTRY return EINA_FALSE;
1015    printf("check %p x lock %i\n", obj, sd->drag_x_locked);
1016    return sd->drag_x_locked;
1017 }
1018
1019 EAPI Eina_Bool
1020 elm_widget_drag_lock_y_get(Evas_Object *obj)
1021 {
1022    API_ENTRY return EINA_FALSE;
1023    printf("check %p y lock %i\n", obj, sd->drag_y_locked);
1024    return sd->drag_y_locked;
1025 }
1026
1027 EAPI int
1028 elm_widget_drag_child_locked_x_get(Evas_Object *obj)
1029 {
1030    API_ENTRY return 0;
1031    return sd->child_drag_x_locked;
1032 }
1033
1034 EAPI int
1035 elm_widget_drag_child_locked_y_get(Evas_Object *obj)
1036 {
1037    API_ENTRY return 0;
1038    return sd->child_drag_y_locked;
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051 /* local subsystem functions */
1052 static void
1053 _smart_reconfigure(Smart_Data *sd)
1054 {
1055    if (sd->resize_obj)
1056      {
1057         evas_object_move(sd->resize_obj, sd->x, sd->y);
1058         evas_object_resize(sd->resize_obj, sd->w, sd->h);
1059      }
1060    if (sd->hover_obj)
1061      {
1062         evas_object_move(sd->hover_obj, sd->x, sd->y);
1063         evas_object_resize(sd->hover_obj, sd->w, sd->h);
1064      }
1065 }
1066
1067 static void
1068 _smart_add(Evas_Object *obj)
1069 {
1070    Smart_Data *sd;
1071
1072    sd = calloc(1, sizeof(Smart_Data));
1073    if (!sd) return;
1074    sd->obj = obj;
1075    sd->x = 0;
1076    sd->y = 0;
1077    sd->w = 0;
1078    sd->h = 0;
1079    sd->can_focus = 1;
1080    evas_object_smart_data_set(obj, sd);
1081 }
1082
1083 static void
1084 _smart_del(Evas_Object *obj)
1085 {
1086    Evas_Object *sobj;
1087
1088    INTERNAL_ENTRY;
1089    if (sd->del_pre_func) sd->del_pre_func(obj);
1090    if (sd->resize_obj)
1091      {
1092         sobj = sd->resize_obj;
1093         sd->resize_obj = NULL;
1094         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1095         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1096         evas_object_del(sobj);
1097      }
1098    if (sd->hover_obj)
1099      {
1100         sobj = sd->hover_obj;
1101         sd->hover_obj = NULL;
1102         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1103         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1104         evas_object_del(sobj);
1105      }
1106    EINA_LIST_FREE(sd->subobjs, sobj)
1107      {
1108         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1109         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1110         evas_object_del(sobj);
1111      }
1112    if (sd->del_func) sd->del_func(obj);
1113    if (sd->style) eina_stringshare_del(sd->style);
1114    if (sd->type) eina_stringshare_del(sd->type);
1115    if (sd->theme) elm_theme_free(sd->theme);
1116    free(sd);
1117 }
1118
1119 static void
1120 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1121 {
1122    INTERNAL_ENTRY;
1123    sd->x = x;
1124    sd->y = y;
1125    _smart_reconfigure(sd);
1126 }
1127
1128 static void
1129 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
1130 {
1131    INTERNAL_ENTRY;
1132    sd->w = w;
1133    sd->h = h;
1134    _smart_reconfigure(sd);
1135 }
1136
1137 static void
1138 _smart_show(Evas_Object *obj)
1139 {
1140    INTERNAL_ENTRY;
1141    evas_object_show(sd->resize_obj);
1142 }
1143
1144 static void
1145 _smart_hide(Evas_Object *obj)
1146 {
1147    INTERNAL_ENTRY;
1148    evas_object_hide(sd->resize_obj);
1149 }
1150
1151 static void
1152 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
1153 {
1154    INTERNAL_ENTRY;
1155    evas_object_color_set(sd->resize_obj, r, g, b, a);
1156 }
1157
1158 static void
1159 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
1160 {
1161    INTERNAL_ENTRY;
1162    evas_object_clip_set(sd->resize_obj, clip);
1163 }
1164
1165 static void
1166 _smart_clip_unset(Evas_Object *obj)
1167 {
1168    INTERNAL_ENTRY;
1169    evas_object_clip_unset(sd->resize_obj);
1170 }
1171
1172 static void
1173 _smart_calculate(Evas_Object *obj)
1174 {
1175    INTERNAL_ENTRY;
1176    if (sd->changed_func) sd->changed_func(obj);
1177 }
1178
1179 /* never need to touch this */
1180
1181 static void
1182 _smart_init(void)
1183 {
1184    if (_e_smart) return;
1185      {
1186         static const Evas_Smart_Class sc =
1187           {
1188              SMART_NAME,
1189                EVAS_SMART_CLASS_VERSION,
1190                _smart_add,
1191                _smart_del,
1192                _smart_move,
1193                _smart_resize,
1194                _smart_show,
1195                _smart_hide,
1196                _smart_color_set,
1197                _smart_clip_set,
1198                _smart_clip_unset,
1199                _smart_calculate,
1200                NULL,
1201                NULL,
1202                NULL,
1203                NULL,
1204                NULL,
1205                NULL
1206           };
1207         _e_smart = evas_smart_class_new(&sc);
1208      }
1209 }
1210
1211 /* utilities */
1212
1213 Eina_List *
1214 _elm_stringlist_get(const char *str)
1215 {
1216    Eina_List *list = NULL;
1217    const char *s, *b;
1218    if (!str) return NULL;
1219    for (b = s = str; 1; s++)
1220      {
1221         if ((*s == ' ') || (*s == 0))
1222           {
1223              char *t = malloc(s - b + 1);
1224              if (t)
1225                {
1226                   strncpy(t, b, s - b);
1227                   t[s - b] = 0;
1228                   list = eina_list_append(list, eina_stringshare_add(t));
1229                   free(t);
1230                }
1231              b = s + 1;
1232           }
1233         if (*s == 0) break;
1234      }
1235    return list;
1236 }
1237
1238 void
1239 _elm_stringlist_free(Eina_List *list)
1240 {
1241    const char *s;
1242    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
1243 }
1244
1245 Eina_Bool
1246 _elm_widget_type_check(const Evas_Object *obj, const char *type)
1247 {
1248    const char *provided, *expected = "(unknown)";
1249    static int abort_on_warn = -1;
1250    provided = elm_widget_type_get(obj);
1251    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
1252    if (type) expected = type;
1253    if ((!provided) || (provided[0] == 0))
1254      {
1255         provided = evas_object_type_get(obj);
1256         if ((!provided) || (provided[0] == 0))
1257           provided = "(unknown)";
1258      }
1259    ERR("Passing Object: %p, of type: '%s' when expecting type: '%s'", obj, provided, expected);
1260    if (abort_on_warn == -1)
1261      {
1262         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1263         else abort_on_warn = 0;
1264      }
1265    if (abort_on_warn == 1) abort();
1266    return EINA_FALSE;
1267 }
1268
1269 static inline Eina_Bool
1270 _elm_widget_is(const Evas_Object *obj)
1271 {
1272    const char *type = evas_object_type_get(obj);
1273    return type == SMART_NAME;
1274 }