1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #include <Elementary.h>
6 #include "elm_priv.h"
7 
8 // FIXME: handle if canvas resizes
9 
10 typedef struct _Widget_Data Widget_Data;
11 
12 struct _Widget_Data
13 {
14    Evas_Object *obj;
15    Evas_Object *content;
16    int last_calc_count;
17    Evas_Coord maxminw, maxminh;
18    Eina_Bool eval : 1;
19    Eina_Bool szeval : 1;
20    Eina_Bool maxmin : 1;
21 };
22 
23 static const char *widtype = NULL;
24 static void _del_hook(Evas_Object *obj);
25 static Eina_Bool _focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next);
26 static void _sizing_eval(Evas_Object *obj);
27 static void _eval(Evas_Object *obj);
28 static void _changed(Evas_Object *obj);
29 static void _move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED);
30 static void _resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED);
31 static void _child_change(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED);
32 static void _child_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED);
33 static void _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content);
34 static Evas_Object *_content_get_hook(const Evas_Object *obj, const char *part);
35 static Evas_Object *_content_unset_hook(Evas_Object *obj, const char *part);
36 
37 static const char SIG_REALIZE[] = "realize";
38 static const char SIG_UNREALIZE[] = "unrealize";
39 
40 static const Evas_Smart_Cb_Description _signals[] = {
41    {SIG_REALIZE, ""},
42    {SIG_UNREALIZE, ""},
43    {NULL, NULL}
44 };
45 
46 static int fac = 0;
47 
48 static void
_del_hook(Evas_Object * obj)49 _del_hook(Evas_Object *obj)
50 {
51    Widget_Data *wd = elm_widget_data_get(obj);
52    if (!wd) return;
53    if (wd->content)
54      {
55         Evas_Object *o = wd->content;
56 
57         evas_object_event_callback_del_full(o,
58                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
59                                             _child_change, obj);
60         evas_object_event_callback_del_full(o,
61                                             EVAS_CALLBACK_DEL,
62                                             _child_del, obj);
63         wd->content = NULL;
64         evas_object_del(o);
65         fac--;
66 //        DBG("FAC-- = %i", fac);
67      }
68    free(wd);
69 }
70 
71 static Eina_Bool
_focus_next_hook(const Evas_Object * obj,Elm_Focus_Direction dir,Evas_Object ** next)72 _focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
73 {
74    Widget_Data *wd = elm_widget_data_get(obj);
75    Evas_Object *cur;
76 
77    if ((!wd) || (!wd->content)) return EINA_FALSE;
78    cur = wd->content;
79    return efl_ui_widget_focus_next_get(cur, dir, next);
80 }
81 
82 static void
_sizing_eval(Evas_Object * obj)83 _sizing_eval(Evas_Object *obj)
84 {
85    Widget_Data *wd = elm_widget_data_get(obj);
86    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
87 
88    if (!wd) return;
89    if (!wd->content) return;
90    evas_object_size_hint_combined_min_get(wd->content, &minw, &minh);
91    evas_object_size_hint_max_get(wd->content, &maxw, &maxh);
92    if (wd->maxmin)
93      {
94         if (minw > wd->maxminw) wd->maxminw = minw;
95         if (minh > wd->maxminh) wd->maxminh = minh;
96         evas_object_size_hint_min_set(obj, wd->maxminw, wd->maxminh);
97      }
98    else
99      {
100         evas_object_size_hint_min_set(obj, minw, minh);
101      }
102    evas_object_size_hint_max_set(obj, maxw, maxh);
103 //   DBG("FAC SZ: %i %i | %i %i", minw, minh, maxw, maxh);
104 }
105 
106 static void
_eval(Evas_Object * obj)107 _eval(Evas_Object *obj)
108 {
109    Evas_Coord x, y, w, h, cvx, cvy, cvw, cvh;
110    Widget_Data *wd = elm_widget_data_get(obj);
111    if (!wd) return;
112 
113    evas_event_freeze(evas_object_evas_get(obj));
114    evas_object_geometry_get(obj, &x, &y, &w, &h);
115    if (w < 1) w = 1;
116    if (h < 1) h = 1;
117    evas_output_viewport_get(evas_object_evas_get(obj),
118                             &cvx, &cvy, &cvw, &cvh);
119    if ((cvw < 1) || (cvh < 1)) return;
120    // need some fuzz value that's beyond the current viewport
121    // for now just make it the viewport * 3 in size (so 1 vp in each direction)
122    /*
123    cvx -= cvw;
124    cvy -= cvh;
125    cvw *= 3;
126    cvh *= 3;
127     */
128    if (ELM_RECTS_INTERSECT(x, y, w, h, cvx, cvy, cvw, cvh))
129      {
130         if (!wd->content)
131           {
132 //             DBG("                 + %i %i %ix%i <> %i %i %ix%i", x, y, w, h, cvx, cvy, cvw, cvh);
133              evas_object_smart_callback_call(obj, SIG_REALIZE, NULL);
134              if (wd->content)
135                {
136                   if (evas_object_smart_data_get(wd->content))
137                      evas_object_smart_calculate(wd->content);
138                }
139              wd->last_calc_count =
140                 evas_smart_objects_calculate_count_get(evas_object_evas_get(obj));
141           }
142      }
143    else
144      {
145         if (wd->content)
146           {
147              if (wd->last_calc_count !=
148                 evas_smart_objects_calculate_count_get(evas_object_evas_get(obj)))
149                 evas_object_smart_callback_call(obj, SIG_UNREALIZE, NULL);
150           }
151      }
152    evas_event_thaw(evas_object_evas_get(obj));
153    evas_event_thaw_eval(evas_object_evas_get(obj));
154 }
155 
156 static void
_changed(Evas_Object * obj)157 _changed(Evas_Object *obj)
158 {
159    Widget_Data *wd = elm_widget_data_get(obj);
160    if (!wd) return;
161    if (wd->eval)
162      {
163         _eval(obj);
164         wd->eval = EINA_FALSE;
165      }
166    if (wd->szeval)
167      {
168         _sizing_eval(obj);
169         wd->szeval = EINA_FALSE;
170      }
171 }
172 
173 static void
_move(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)174 _move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
175 {
176    Widget_Data *wd = elm_widget_data_get(obj);
177    if (!wd) return;
178    wd->eval = EINA_TRUE;
179    evas_object_smart_changed(obj);
180 }
181 
182 static void
_resize(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)183 _resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
184 {
185    Widget_Data *wd = elm_widget_data_get(obj);
186    if (!wd) return;
187    wd->eval = EINA_TRUE;
188    evas_object_smart_changed(obj);
189 }
190 
191 static void
_child_change(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)192 _child_change(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
193 {
194    Widget_Data *wd = elm_widget_data_get(data);
195    if (!wd) return;
196    wd->eval = EINA_TRUE;
197    wd->szeval = EINA_TRUE;
198    evas_object_smart_changed(data);
199 }
200 
201 static void
_child_del(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)202 _child_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
203 {
204    Evas_Object *fobj = data;
205    Widget_Data *wd = elm_widget_data_get(fobj);
206    if (!wd) return;
207    if (wd->content != obj) return;
208    evas_object_event_callback_del_full(wd->content,
209                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
210                                        _child_change, obj);
211    evas_object_event_callback_del_full(wd->content,
212                                        EVAS_CALLBACK_DEL,
213                                        _child_del, obj);
214    wd->content = NULL;
215    fac--;
216 //   DBG("FAC-- = %i", fac);
217 }
218 
219 static Evas_Object *
_content_unset_hook(Evas_Object * obj,const char * part)220 _content_unset_hook(Evas_Object *obj, const char *part)
221 {
222    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
223    Widget_Data *wd;
224    Evas_Object *content;
225 
226    if (part && strcmp(part, "default")) return NULL;
227    wd = elm_widget_data_get(obj);
228    if (!wd || !wd->content) return NULL;
229 
230    content = wd->content;
231    evas_object_event_callback_del_full(content,
232                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
233                                        _child_change, obj);
234    evas_object_event_callback_del_full(content,
235                                        EVAS_CALLBACK_DEL,
236                                        _child_del, obj);
237    wd->content = NULL;
238    fac--;
239 //         DBG("FAC-- = %i", fac);
240    return content;
241 }
242 
243 static void
_content_set_hook(Evas_Object * obj,const char * part,Evas_Object * content)244 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
245 {
246    ELM_CHECK_WIDTYPE(obj, widtype);
247    Widget_Data *wd;
248    Evas_Object *prev_content;
249 
250    if (part && strcmp(part, "default")) return;
251    wd = elm_widget_data_get(obj);
252    if (!wd) return;
253    if (wd->content == content) return;
254 
255    prev_content = _content_unset_hook(obj, part);
256    evas_object_del(prev_content);
257 
258    wd->content = content;
259    if (!content) return;
260 
261    elm_widget_resize_object_set(obj, content);
262    evas_object_event_callback_add(content, EVAS_CALLBACK_DEL, _child_del, obj);
263    evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
264                                   _child_change, obj);
265    wd->eval = EINA_TRUE;
266    wd->szeval = EINA_TRUE;
267    evas_object_smart_changed(obj);
268    fac++;
269 }
270 
271 static Evas_Object *
_content_get_hook(const Evas_Object * obj,const char * part)272 _content_get_hook(const Evas_Object *obj, const char *part)
273 {
274    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
275    Widget_Data *wd;
276    if (part && strcmp(part, "default")) return NULL;
277    wd = elm_widget_data_get(obj);
278    if (!wd) return NULL;
279    return wd->content;
280 }
281 
282 EAPI Evas_Object *
elm_factory_add(Evas_Object * parent)283 elm_factory_add(Evas_Object *parent)
284 {
285    Evas_Object *obj;
286    Evas *e;
287    Widget_Data *wd;
288 
289    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
290 
291    ELM_SET_WIDTYPE(widtype, "factory");
292    elm_widget_type_set(obj, "factory");
293    elm_widget_sub_object_add(parent, obj);
294    elm_widget_data_set(obj, wd);
295    elm_widget_del_hook_set(obj, _del_hook);
296    efl_ui_widget_focus_next_hook_set(obj, _focus_next_hook);
297    elm_widget_content_set_hook_set(obj, _content_set_hook);
298    elm_widget_content_get_hook_set(obj, _content_get_hook);
299    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
300    elm_widget_can_focus_set(obj, EINA_FALSE);
301    elm_widget_changed_hook_set(obj, _changed);
302 
303    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
304    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
305 
306    evas_object_smart_callbacks_descriptions_set(obj, _signals);
307 
308    wd->obj = obj;
309    wd->last_calc_count = -1;
310    return obj;
311 }
312 
313 EAPI void
elm_factory_maxmin_mode_set(Evas_Object * obj,Eina_Bool enabled)314 elm_factory_maxmin_mode_set(Evas_Object *obj, Eina_Bool enabled)
315 {
316    ELM_CHECK_WIDTYPE(obj, widtype);
317    Widget_Data *wd = elm_widget_data_get(obj);
318    if (!wd) return;
319    wd->maxmin = !!enabled;
320 }
321 
322 EAPI Eina_Bool
elm_factory_maxmin_mode_get(const Evas_Object * obj)323 elm_factory_maxmin_mode_get(const Evas_Object *obj)
324 {
325    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
326    Widget_Data *wd = elm_widget_data_get(obj);
327    if (!wd) return EINA_FALSE;
328    return wd->maxmin;
329 }
330 
331 EAPI void
elm_factory_maxmin_reset_set(Evas_Object * obj)332 elm_factory_maxmin_reset_set(Evas_Object *obj)
333 {
334    ELM_CHECK_WIDTYPE(obj, widtype);
335    Widget_Data *wd = elm_widget_data_get(obj);
336    if (!wd) return;
337    wd->maxminw = 0;
338    wd->maxminh = 0;
339    wd->eval = EINA_TRUE;
340    wd->szeval = EINA_TRUE;
341    evas_object_smart_changed(obj);
342 }
343