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