Merge branch 'master' of 165.213.180.234:/git/slp/pkgs/elementary
[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    else
798      {
799         Evas_Object *parent_obj;
800         do
801           {
802              parent_obj = sd->parent_obj;                
803              sd = evas_object_smart_data_get(parent_obj);
804              if ((!parent_obj) || (!sd) || (!_elm_widget_is(parent_obj))) break;
805              if (sd->on_show_region_func)
806                {
807                   sd->on_show_region_func(sd->on_show_region_data, obj);
808                   break;
809                }
810           }
811         while (parent_obj);
812      }
813 }
814
815 EAPI void
816 elm_widget_show_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
817 {
818    API_ENTRY return;
819    if (x) *x = sd->rx;
820    if (y) *y = sd->ry;
821    if (w) *w = sd->rw;
822    if (h) *h = sd->rh;
823 }
824
825 EAPI void
826 elm_widget_scroll_hold_push(Evas_Object *obj)
827 {
828    API_ENTRY return;
829    sd->scroll_hold++;
830    if (sd->scroll_hold == 1)
831      evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
832    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
833    // FIXME: on delete/reparent hold pop
834 }
835
836 EAPI void
837 elm_widget_scroll_hold_pop(Evas_Object *obj)
838 {
839    API_ENTRY return;
840    sd->scroll_hold--;
841    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
842    if (sd->scroll_hold == 0)
843      evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
844    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
845 }
846
847 EAPI int
848 elm_widget_scroll_hold_get(const Evas_Object *obj)
849 {
850    API_ENTRY return 0;
851    return sd->scroll_hold;
852 }
853
854 EAPI void
855 elm_widget_scroll_freeze_push(Evas_Object *obj)
856 {
857    API_ENTRY return;
858    sd->scroll_freeze++;
859    if (sd->scroll_freeze == 1)
860      evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
861    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
862    // FIXME: on delete/reparent freeze pop
863 }
864
865 EAPI void
866 elm_widget_scroll_freeze_pop(Evas_Object *obj)
867 {
868    API_ENTRY return;
869    sd->scroll_freeze--;
870    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
871    if (sd->scroll_freeze == 0)
872      evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
873    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
874 }
875
876 EAPI int
877 elm_widget_scroll_freeze_get(const Evas_Object *obj)
878 {
879    API_ENTRY return 0;
880    return sd->scroll_freeze;
881 }
882
883 EAPI void
884 elm_widget_scale_set(Evas_Object *obj, double scale)
885 {
886    API_ENTRY return;
887    if (scale <= 0.0) scale = 0.0;
888    if (sd->scale != scale)
889      {
890         sd->scale = scale;
891         elm_widget_theme(obj);
892      }
893 }
894
895 EAPI double
896 elm_widget_scale_get(const Evas_Object *obj)
897 {
898    API_ENTRY return 1.0;
899    // FIXME: save walking up the tree by storingcaching parent scale
900    if (sd->scale == 0.0)
901      {
902         if (sd->parent_obj)
903           return elm_widget_scale_get(sd->parent_obj);
904         else
905           return 1.0;
906      }
907    return sd->scale;
908 }
909
910 EAPI void
911 elm_widget_theme_set(Evas_Object *obj, Elm_Theme *th)
912 {
913    API_ENTRY return;
914    if (sd->theme != th)
915      {
916         if (sd->theme) elm_theme_free(sd->theme);
917         sd->theme = th;
918         if (th) th->ref++;
919         elm_widget_theme(obj);
920      }
921 }
922
923 EAPI Elm_Theme *
924 elm_widget_theme_get(const Evas_Object *obj)
925 {
926    API_ENTRY return NULL;
927    if (!sd->theme)
928      {
929         if (sd->parent_obj)
930           return elm_widget_theme_get(sd->parent_obj);
931         else
932           return NULL;
933      }
934    return sd->theme;
935 }
936
937 EAPI void
938 elm_widget_style_set(Evas_Object *obj, const char *style)
939 {
940    API_ENTRY return;
941
942    if (eina_stringshare_replace(&sd->style, style))
943      elm_widget_theme(obj);
944 }
945
946 EAPI const char *
947 elm_widget_style_get(const Evas_Object *obj)
948 {
949    API_ENTRY return "";
950    if (sd->style) return sd->style;
951    return "default";
952 }
953
954 EAPI void
955 elm_widget_type_set(Evas_Object *obj, const char *type)
956 {
957    API_ENTRY return;
958    eina_stringshare_replace(&sd->type, type);
959 }
960
961 EAPI const char *
962 elm_widget_type_get(const Evas_Object *obj)
963 {
964    API_ENTRY return "";
965    if (sd->type) return sd->type;
966    return "";
967 }
968
969
970
971
972
973
974
975
976
977 static void
978 _propagate_x_drag_lock(Evas_Object *obj, int dir)
979 {
980    Smart_Data *sd = evas_object_smart_data_get(obj);
981    if (sd->parent_obj)
982      {
983         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
984         if (sd2)
985           {
986              sd2->child_drag_x_locked += dir;
987              _propagate_x_drag_lock(sd->parent_obj, dir);
988           }
989      }
990 }
991
992 static void
993 _propagate_y_drag_lock(Evas_Object *obj, int dir)
994 {
995    Smart_Data *sd = evas_object_smart_data_get(obj);
996    if (sd->parent_obj)
997      {
998         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
999         if (sd2)
1000           {
1001              sd2->child_drag_y_locked += dir;
1002              _propagate_y_drag_lock(sd->parent_obj, dir);
1003           }
1004      }
1005 }
1006
1007 EAPI void
1008 elm_widget_drag_lock_x_set(Evas_Object *obj, Eina_Bool lock)
1009 {
1010    API_ENTRY return;
1011    if (sd->drag_x_locked == lock) return;
1012    sd->drag_x_locked = lock;
1013    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
1014    else _propagate_x_drag_lock(obj, -1);
1015 }
1016
1017 EAPI void
1018 elm_widget_drag_lock_y_set(Evas_Object *obj, Eina_Bool lock)
1019 {
1020    API_ENTRY return;
1021    if (sd->drag_y_locked == lock) return;
1022    sd->drag_y_locked = lock;
1023    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
1024    else _propagate_y_drag_lock(obj, -1);
1025 }
1026
1027 EAPI Eina_Bool
1028 elm_widget_drag_lock_x_get(Evas_Object *obj)
1029 {
1030    API_ENTRY return EINA_FALSE;
1031    printf("check %p x lock %i\n", obj, sd->drag_x_locked);
1032    return sd->drag_x_locked;
1033 }
1034
1035 EAPI Eina_Bool
1036 elm_widget_drag_lock_y_get(Evas_Object *obj)
1037 {
1038    API_ENTRY return EINA_FALSE;
1039    printf("check %p y lock %i\n", obj, sd->drag_y_locked);
1040    return sd->drag_y_locked;
1041 }
1042
1043 EAPI int
1044 elm_widget_drag_child_locked_x_get(Evas_Object *obj)
1045 {
1046    API_ENTRY return 0;
1047    return sd->child_drag_x_locked;
1048 }
1049
1050 EAPI int
1051 elm_widget_drag_child_locked_y_get(Evas_Object *obj)
1052 {
1053    API_ENTRY return 0;
1054    return sd->child_drag_y_locked;
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 /* local subsystem functions */
1068 static void
1069 _smart_reconfigure(Smart_Data *sd)
1070 {
1071    if (sd->resize_obj)
1072      {
1073         evas_object_move(sd->resize_obj, sd->x, sd->y);
1074         evas_object_resize(sd->resize_obj, sd->w, sd->h);
1075      }
1076    if (sd->hover_obj)
1077      {
1078         evas_object_move(sd->hover_obj, sd->x, sd->y);
1079         evas_object_resize(sd->hover_obj, sd->w, sd->h);
1080      }
1081 }
1082
1083 static void
1084 _smart_add(Evas_Object *obj)
1085 {
1086    Smart_Data *sd;
1087
1088    sd = calloc(1, sizeof(Smart_Data));
1089    if (!sd) return;
1090    sd->obj = obj;
1091    sd->x = 0;
1092    sd->y = 0;
1093    sd->w = 0;
1094    sd->h = 0;
1095    sd->can_focus = 1;
1096    evas_object_smart_data_set(obj, sd);
1097 }
1098
1099 static void
1100 _smart_del(Evas_Object *obj)
1101 {
1102    Evas_Object *sobj;
1103
1104    INTERNAL_ENTRY;
1105    if (sd->del_pre_func) sd->del_pre_func(obj);
1106    if (sd->resize_obj)
1107      {
1108         sobj = sd->resize_obj;
1109         sd->resize_obj = NULL;
1110         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1111         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1112         evas_object_del(sobj);
1113      }
1114    if (sd->hover_obj)
1115      {
1116         sobj = sd->hover_obj;
1117         sd->hover_obj = NULL;
1118         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1119         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1120         evas_object_del(sobj);
1121      }
1122    EINA_LIST_FREE(sd->subobjs, sobj)
1123      {
1124         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
1125         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
1126         evas_object_del(sobj);
1127      }
1128    if (sd->del_func) sd->del_func(obj);
1129    if (sd->style) eina_stringshare_del(sd->style);
1130    if (sd->type) eina_stringshare_del(sd->type);
1131    if (sd->theme) elm_theme_free(sd->theme);
1132    free(sd);
1133 }
1134
1135 static void
1136 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1137 {
1138    INTERNAL_ENTRY;
1139    sd->x = x;
1140    sd->y = y;
1141    _smart_reconfigure(sd);
1142 }
1143
1144 static void
1145 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
1146 {
1147    INTERNAL_ENTRY;
1148    sd->w = w;
1149    sd->h = h;
1150    _smart_reconfigure(sd);
1151 }
1152
1153 static void
1154 _smart_show(Evas_Object *obj)
1155 {
1156    INTERNAL_ENTRY;
1157    evas_object_show(sd->resize_obj);
1158 }
1159
1160 static void
1161 _smart_hide(Evas_Object *obj)
1162 {
1163    INTERNAL_ENTRY;
1164    evas_object_hide(sd->resize_obj);
1165 }
1166
1167 static void
1168 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
1169 {
1170    INTERNAL_ENTRY;
1171    evas_object_color_set(sd->resize_obj, r, g, b, a);
1172 }
1173
1174 static void
1175 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
1176 {
1177    INTERNAL_ENTRY;
1178    evas_object_clip_set(sd->resize_obj, clip);
1179 }
1180
1181 static void
1182 _smart_clip_unset(Evas_Object *obj)
1183 {
1184    INTERNAL_ENTRY;
1185    evas_object_clip_unset(sd->resize_obj);
1186 }
1187
1188 static void
1189 _smart_calculate(Evas_Object *obj)
1190 {
1191    INTERNAL_ENTRY;
1192    if (sd->changed_func) sd->changed_func(obj);
1193 }
1194
1195 /* never need to touch this */
1196
1197 static void
1198 _smart_init(void)
1199 {
1200    if (_e_smart) return;
1201      {
1202         static const Evas_Smart_Class sc =
1203           {
1204              SMART_NAME,
1205                EVAS_SMART_CLASS_VERSION,
1206                _smart_add,
1207                _smart_del,
1208                _smart_move,
1209                _smart_resize,
1210                _smart_show,
1211                _smart_hide,
1212                _smart_color_set,
1213                _smart_clip_set,
1214                _smart_clip_unset,
1215                _smart_calculate,
1216                NULL,
1217                NULL,
1218                NULL,
1219                NULL,
1220                NULL,
1221                NULL
1222           };
1223         _e_smart = evas_smart_class_new(&sc);
1224      }
1225 }
1226
1227 /* utilities */
1228
1229 Eina_List *
1230 _elm_stringlist_get(const char *str)
1231 {
1232    Eina_List *list = NULL;
1233    const char *s, *b;
1234    if (!str) return NULL;
1235    for (b = s = str; 1; s++)
1236      {
1237         if ((*s == ' ') || (*s == 0))
1238           {
1239              char *t = malloc(s - b + 1);
1240              if (t)
1241                {
1242                   strncpy(t, b, s - b);
1243                   t[s - b] = 0;
1244                   list = eina_list_append(list, eina_stringshare_add(t));
1245                   free(t);
1246                }
1247              b = s + 1;
1248           }
1249         if (*s == 0) break;
1250      }
1251    return list;
1252 }
1253
1254 void
1255 _elm_stringlist_free(Eina_List *list)
1256 {
1257    const char *s;
1258    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
1259 }
1260
1261 Eina_Bool
1262 _elm_widget_type_check(const Evas_Object *obj, const char *type)
1263 {
1264    const char *provided, *expected = "(unknown)";
1265    static int abort_on_warn = -1;
1266    provided = elm_widget_type_get(obj);
1267    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
1268    if (type) expected = type;
1269    if ((!provided) || (provided[0] == 0))
1270      {
1271         provided = evas_object_type_get(obj);
1272         if ((!provided) || (provided[0] == 0))
1273           provided = "(unknown)";
1274      }
1275    ERR("Passing Object: %p, of type: '%s' when expecting type: '%s'", obj, provided, expected);
1276    if (abort_on_warn == -1)
1277      {
1278         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1279         else abort_on_warn = 0;
1280      }
1281    if (abort_on_warn == 1) abort();
1282    return EINA_FALSE;
1283 }
1284
1285 static inline Eina_Bool
1286 _elm_widget_is(const Evas_Object *obj)
1287 {
1288    const char *type = evas_object_type_get(obj);
1289    return type == SMART_NAME;
1290 }