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