1 #include <Elementary.h>
5 # define MIN(a,b) ((a) < (b)) ? (a) : (b)
9 # define MAX(a,b) ((a) < (b)) ? (b) : (a)
12 typedef struct _Widget_Data Widget_Data;
16 Evas_Object *shelf, *panel, *virtualkeypad, *sliding_win;
18 Evas_Object *scroller;
20 int is_sliding_win_visible;
21 #ifdef HAVE_ELEMENTARY_X
22 Ecore_Event_Handler *prop_hdl;
23 Ecore_X_Virtual_Keyboard_State vkb_state;
27 Ecore_Animator *animator; // animaton timer
28 double start; // time started
29 Evas_Coord auto_x, auto_y; // desired delta
30 Evas_Coord x, y; // current delta
32 Ecore_Job *show_region_job;
35 /* Enum to identify conformant swallow parts */
36 typedef enum _Conformant_Part_Type Conformant_Part_Type;
37 enum _Conformant_Part_Type
39 ELM_CONFORM_INDICATOR_PART = 1,
40 ELM_CONFORM_SOFTKEY_PART = 2,
41 ELM_CONFORM_VIRTUAL_KEYPAD_PART = 4,
42 ELM_CONFORM_SLIDING_WIN_PART = 8
45 #define SUB_TYPE_COUNT 2
46 static char *sub_type[SUB_TYPE_COUNT] = { "scroller", "genlist" };
48 /* local function prototypes */
49 static const char *widtype = NULL;
50 static void _del_pre_hook(Evas_Object *obj);
51 static void _del_hook(Evas_Object *obj);
52 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
53 static void _theme_hook(Evas_Object *obj);
54 static void _content_set_hook(Evas_Object *obj,
56 Evas_Object *content);
57 static Evas_Object *_content_get_hook(const Evas_Object *obj,
59 static Evas_Object *_content_unset_hook(Evas_Object *obj, const char *part);
60 static void _swallow_conformant_parts(Evas_Object *obj);
61 static void _conformant_part_size_set(Evas_Object *obj,
67 static void _conformant_part_sizing_eval(Evas_Object *obj,
68 Conformant_Part_Type part_type);
69 static void _conformant_move_resize_event_cb(void *data,
73 static void _sizing_eval(Evas_Object *obj);
74 static void _show_region_job(void *data);
75 static Eina_Bool _prop_change(void *data, int type, void *event);
76 static void _changed_size_hints(void *data, Evas *e,
82 _del_pre_hook(Evas_Object *obj)
84 Widget_Data *wd = elm_widget_data_get(obj);
86 #ifdef HAVE_ELEMENTARY_X
87 if (wd->prop_hdl) ecore_event_handler_del(wd->prop_hdl);
92 _del_hook(Evas_Object *obj)
94 Widget_Data *wd = elm_widget_data_get(obj);
97 if (wd->show_region_job) ecore_job_del(wd->show_region_job);
102 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
104 Widget_Data *wd = elm_widget_data_get(obj);
107 edje_object_mirrored_set(wd->base, rtl);
111 _theme_hook(Evas_Object *obj)
113 Widget_Data *wd = elm_widget_data_get(obj);
116 _elm_widget_mirrored_reload(obj);
117 _mirrored_set(obj, elm_widget_mirrored_get(obj));
118 _elm_theme_object_set(obj, wd->base, "conformant", "base",
119 elm_widget_style_get(obj));
120 _swallow_conformant_parts(obj);
123 edje_object_part_swallow(wd->base, "elm.swallow.content", wd->content);
124 edje_object_scale_set(wd->base, elm_widget_scale_get(obj)
125 * _elm_config->scale);
130 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
132 ELM_CHECK_WIDTYPE(obj, widtype);
135 if (part && strcmp(part, "default")) return;
136 wd = elm_widget_data_get(obj);
138 if (wd->content == content) return;
139 if (wd->content) evas_object_del(wd->content);
140 wd->content = content;
143 elm_widget_sub_object_add(obj, content);
144 evas_object_event_callback_add(content,
145 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
146 _changed_size_hints, obj);
147 edje_object_part_swallow(wd->base, "elm.swallow.content", content);
153 _content_get_hook(const Evas_Object *obj, const char *part)
155 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
158 if (part && strcmp(part, "default")) return NULL;
159 wd = elm_widget_data_get(obj);
160 if (!wd) return NULL;
165 _content_unset_hook(Evas_Object *obj, const char *part)
167 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
169 Evas_Object *content;
170 if (part && strcmp(part, "default")) return NULL;
171 wd = elm_widget_data_get(obj);
172 if ((!wd) || (!wd->content)) return NULL;
173 content = wd->content;
174 elm_widget_sub_object_del(obj, wd->content);
175 evas_object_event_callback_del_full(wd->content,
176 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
177 _changed_size_hints, obj);
178 edje_object_part_unswallow(wd->base, wd->content);
184 _sizing_eval(Evas_Object *obj)
186 Widget_Data *wd = elm_widget_data_get(obj);
187 Evas_Coord mw = -1, mh = -1;
190 edje_object_size_min_calc(wd->base, &mw, &mh);
191 evas_object_size_hint_min_set(obj, mw, mh);
192 evas_object_size_hint_max_set(obj, -1, -1);
195 /* Example of env vars:
196 * ILLUME_KBD="0, 0, 800, 301"
197 * ILLUME_IND=0,0,800,32
198 * ILLUME_STK="0,568,800,32
201 _conformant_part_geometry_env_get(const char *part, int *sx, int *sy, int *sw, int *sh)
203 const char delimiters[] = " ,;";
204 char *env_val, *token;
208 if (!(env_val = getenv(part))) return EINA_FALSE;
210 /* strtok would modify env var if not copied to a buffer */
211 strncpy(buf, env_val, sizeof(buf));
213 token = strtok(buf, delimiters);
214 if (!token) return EINA_FALSE;
217 token = strtok(NULL, delimiters);
218 if (!token) return EINA_FALSE;
221 token = strtok(NULL, delimiters);
222 if (!token) return EINA_FALSE;
225 token = strtok(NULL, delimiters);
226 if (!token) return EINA_FALSE;
237 _conformant_part_size_set(Evas_Object *obj, Evas_Object *sobj, Evas_Coord sx,
238 Evas_Coord sy, Evas_Coord sw, Evas_Coord sh)
240 Evas_Coord cx, cy, cw, ch;
241 Evas_Coord part_height = 0, part_width = 0;
243 evas_object_geometry_get(obj, &cx, &cy, &cw, &ch);
245 /* Part overlapping with conformant */
246 if ((cx < (sx + sw)) && ((cx + cw) > sx)
247 && (cy < (sy + sh)) && ((cy + ch) > sy))
249 part_height = MIN((cy + ch), (sy + sh)) - MAX(cy, sy);
250 part_width = MIN((cx + cw), (sx + sw)) - MAX(cx, sx);
253 evas_object_size_hint_min_set(sobj, part_width, part_height);
254 evas_object_size_hint_max_set(sobj, part_width, part_height);
258 _conformant_part_sizing_eval(Evas_Object *obj, Conformant_Part_Type part_type)
260 Ecore_X_Window zone = 0, xwin;
262 int sx = -1, sy = -1, sw = -1, sh = -1;
263 Widget_Data *wd = elm_widget_data_get(obj);
267 top = elm_widget_top_get(obj);
268 #ifdef HAVE_ELEMENTARY_X
269 xwin = elm_win_xwindow_get(top);
271 zone = ecore_x_e_illume_zone_get(xwin);
274 if (part_type & ELM_CONFORM_INDICATOR_PART)
276 if ((!_conformant_part_geometry_env_get("ILLUME_IND",
277 &sx, &sy, &sw, &sh)) && (xwin))
279 #ifdef HAVE_ELEMENTARY_X
280 //No information of the indicator geometry, reset the geometry.
281 if (!ecore_x_e_illume_indicator_geometry_get(zone, &sx, &sy, &sw, &sh))
282 sx = sy = sw = sh = 0;
287 _conformant_part_size_set(obj, wd->shelf, sx, sy, sw, sh);
289 if (part_type & ELM_CONFORM_VIRTUAL_KEYPAD_PART)
291 if ((!_conformant_part_geometry_env_get("ILLUME_KBD",
292 &sx, &sy, &sw, &sh)) && (xwin))
294 #ifdef HAVE_ELEMENTARY_X
295 //No information of the keyboard geometry, reset the geometry.
296 if (!ecore_x_e_illume_keyboard_geometry_get(zone, &sx, &sy, &sw, &sh))
297 sx = sy = sw = sh = 0;
302 _conformant_part_size_set(obj,wd->virtualkeypad, sx, sy, sw, sh);
304 if (part_type & ELM_CONFORM_SOFTKEY_PART)
306 if ((!_conformant_part_geometry_env_get("ILLUME_STK",
307 &sx, &sy, &sw, &sh)) && (xwin))
309 #ifdef HAVE_ELEMENTARY_X
310 //No information of the softkey geometry, reset the geometry.
311 if (!ecore_x_e_illume_softkey_geometry_get(zone, &sx, &sy, &sw, &sh))
312 sx = sy = sw = sh = 0;
317 _conformant_part_size_set(obj, wd->panel, sx, sy, sw, sh);
322 _swallow_conformant_parts(Evas_Object *obj)
324 Widget_Data *wd = elm_widget_data_get(obj);
329 wd->shelf = evas_object_rectangle_add(evas_object_evas_get(obj));
330 elm_widget_sub_object_add(obj, wd->shelf);
331 evas_object_size_hint_min_set(wd->shelf, -1, 0);
332 evas_object_size_hint_max_set(wd->shelf, -1, 0);
335 _conformant_part_sizing_eval(obj, ELM_CONFORM_INDICATOR_PART);
336 evas_object_color_set(wd->shelf, 0, 0, 0, 0);
337 edje_object_part_swallow(wd->base, "elm.swallow.shelf", wd->shelf);
339 if (!wd->virtualkeypad)
341 wd->virtualkeypad = evas_object_rectangle_add(evas_object_evas_get(obj));
342 elm_widget_sub_object_add(obj, wd->virtualkeypad);
343 evas_object_size_hint_min_set(wd->virtualkeypad, -1, 0);
344 evas_object_size_hint_max_set(wd->virtualkeypad, -1, 0);
347 _conformant_part_sizing_eval(obj, ELM_CONFORM_VIRTUAL_KEYPAD_PART);
348 evas_object_color_set(wd->virtualkeypad, 0, 0, 0, 0);
349 edje_object_part_swallow(wd->base, "elm.swallow.virtualkeypad",
352 if (!wd->sliding_win)
354 wd->sliding_win = evas_object_rectangle_add(evas_object_evas_get(obj));
355 elm_widget_sub_object_add(obj, wd->sliding_win);
356 evas_object_size_hint_min_set(wd->sliding_win, -1, 0);
357 evas_object_size_hint_max_set(wd->sliding_win, -1, 0);
359 #ifdef HAVE_ELEMENTARY_X
361 _conformant_part_sizing_eval(obj, ELM_CONFORM_SLIDING_WIN_PART);
363 evas_object_color_set(wd->sliding_win, 0, 0, 0, 0);
367 wd->panel = evas_object_rectangle_add(evas_object_evas_get(obj));
368 elm_widget_sub_object_add(obj, wd->panel);
369 evas_object_size_hint_min_set(wd->panel, -1, 0);
370 evas_object_size_hint_max_set(wd->panel, -1, 0);
373 _conformant_part_sizing_eval(obj, ELM_CONFORM_SOFTKEY_PART);
374 evas_object_color_set(wd->panel, 0, 0, 0, 0);
375 edje_object_part_swallow(wd->base, "elm.swallow.panel", wd->panel);
379 _changed_size_hints(void *data, Evas *e __UNUSED__,
380 Evas_Object *obj __UNUSED__,
381 void *event_info __UNUSED__)
383 Widget_Data *wd = elm_widget_data_get(data);
390 _sub_del(void *data, Evas_Object *obj __UNUSED__, void *event_info)
392 Widget_Data *wd = elm_widget_data_get(data);
393 Evas_Object *sub = event_info;
395 if (sub == wd->content)
397 evas_object_event_callback_del_full(sub,
398 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
399 _changed_size_hints, data);
405 /* unused now - but meant to be for making sure the focused widget is always
406 * visible when the vkbd comes and goes by moving the conformant obj (and thus
407 * its children) to show the focused widget (and if focus changes follow)
410 _focus_object_get(const Evas_Object *obj)
412 Evas_Object *win, *foc;
414 win = elm_widget_top_get(obj);
415 if (!win) return NULL;
416 foc = elm_widget_top_get(win);
420 _focus_object_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
422 evas_object_geometry_get(obj, x, y, w, h);
426 _focus_change_del(void *data, Evas_Object *obj, void *event_info)
428 // called from toplevel when the focused window shanges
432 _autoscroll_move(Evas_Object *obj)
434 // move conformant edje by delta to show focused widget
438 _autoscroll_mode_enable(Evas_Object *obj)
440 // called when autoscroll mode should be on - content area smaller than
442 // 1. get focused object
443 // 2. if not in visible conformant area calculate delta needed to
445 // 3. store delta and call _autoscroll_move() which either asanimates
446 // or jumps right there
450 _autoscroll_mode_disable(Evas_Object *obj)
452 // called when autoscroll mode should be off - set delta to 0 and
453 // call _autoscroll_move()
458 _conformant_move_resize_event_cb(void *data __UNUSED__, Evas *e __UNUSED__,
459 Evas_Object *obj, void *event_info __UNUSED__)
461 Conformant_Part_Type part_type;
462 Widget_Data *wd = elm_widget_data_get(obj);
465 part_type = (ELM_CONFORM_INDICATOR_PART |
466 ELM_CONFORM_SOFTKEY_PART |
467 ELM_CONFORM_VIRTUAL_KEYPAD_PART |
468 ELM_CONFORM_SLIDING_WIN_PART);
469 _conformant_part_sizing_eval(obj, part_type);
472 // showing the focused/important region.
474 _content_resize_event_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj
475 __UNUSED__, void *event_info __UNUSED__)
477 Evas_Object *conformant = (Evas_Object *)data;
478 Widget_Data *wd = elm_widget_data_get(conformant);
481 #ifdef HAVE_ELEMENTARY_X
482 if ((wd->vkb_state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
483 && (!wd->is_sliding_win_visible)) return;
486 if (wd->show_region_job) ecore_job_del(wd->show_region_job);
487 wd->show_region_job = ecore_job_add(_show_region_job, conformant);
491 _show_region_job(void *data)
493 Evas_Object *focus_obj;
494 Evas_Object *conformant = (Evas_Object *)data;
495 Widget_Data *wd = elm_widget_data_get(conformant);
499 focus_obj = elm_widget_focused_object_get(conformant);
502 Evas_Coord x, y, w, h;
504 elm_widget_show_region_get(focus_obj, &x, &y, &w, &h);
506 if (h < _elm_config->finger_size)
507 h = _elm_config->finger_size;
509 elm_widget_show_region_set(focus_obj, x, y, w, h, EINA_TRUE);
512 wd->show_region_job = NULL;
515 #ifdef HAVE_ELEMENTARY_X
517 _update_autoscroll_objs(void *data)
521 Evas_Object *sub, *top_scroller = NULL;
522 Evas_Object *conformant = (Evas_Object *)data;
523 Widget_Data *wd = elm_widget_data_get(data);
527 sub = elm_widget_focused_object_get(conformant);
528 //Look up for Top most scroller in the Focus Object hierarchy inside Conformant.
532 type = elm_widget_type_get(sub);
533 if (!strcmp(type, "conformant")) break;
534 for (i = 0; i < SUB_TYPE_COUNT; i++)
535 if (!strcmp(type, sub_type[i]))
540 sub = elm_object_parent_widget_get(sub);
543 //If the scroller got changed by app, replace it.
544 if (top_scroller != wd->scroller)
546 if (wd->scroller) evas_object_event_callback_del(wd->scroller,
547 EVAS_CALLBACK_RESIZE,
548 _content_resize_event_cb);
549 wd->scroller = top_scroller;
550 if (wd->scroller) evas_object_event_callback_add(wd->scroller,
551 EVAS_CALLBACK_RESIZE,
552 _content_resize_event_cb,
558 _prop_change(void *data, int type __UNUSED__, void *event)
560 Ecore_X_Event_Window_Property *ev;
561 Widget_Data *wd = elm_widget_data_get(data);
563 if (!wd) return ECORE_CALLBACK_PASS_ON;
565 if (ev->atom == ECORE_X_ATOM_E_ILLUME_ZONE)
567 Conformant_Part_Type part_type;
569 part_type = (ELM_CONFORM_INDICATOR_PART |
570 ELM_CONFORM_SOFTKEY_PART |
571 ELM_CONFORM_VIRTUAL_KEYPAD_PART |
572 ELM_CONFORM_SLIDING_WIN_PART);
573 _conformant_part_sizing_eval(data, part_type);
575 else if (ev->atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY)
576 _conformant_part_sizing_eval(data, ELM_CONFORM_INDICATOR_PART);
577 else if (ev->atom == ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY)
578 _conformant_part_sizing_eval(data, ELM_CONFORM_SOFTKEY_PART);
579 else if (ev->atom == ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY)
580 _conformant_part_sizing_eval(data, ELM_CONFORM_VIRTUAL_KEYPAD_PART);
581 else if (ev->atom == ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY)
582 _conformant_part_sizing_eval(data, ELM_CONFORM_SLIDING_WIN_PART);
583 else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
587 printf("Keyboard Geometry Changed\n");
588 zone = ecore_x_e_illume_zone_get(ev->win);
589 wd->vkb_state = ecore_x_e_virtual_keyboard_state_get(zone);
590 if (wd->vkb_state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
592 evas_object_size_hint_min_set(wd->virtualkeypad, -1, 0);
593 evas_object_size_hint_max_set(wd->virtualkeypad, -1, 0);
596 _update_autoscroll_objs(data);
598 else if (ev->atom == ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE)
602 zone = ecore_x_e_illume_zone_get(ev->win);
603 wd->is_sliding_win_visible = ecore_x_e_illume_sliding_win_state_get(zone);
605 if (!wd->is_sliding_win_visible)
607 evas_object_size_hint_min_set(wd->sliding_win, -1, 0);
608 evas_object_size_hint_max_set(wd->sliding_win, -1, 0);
611 _update_autoscroll_objs(data);
614 return ECORE_CALLBACK_PASS_ON;
619 elm_conformant_add(Evas_Object *parent)
625 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
627 ELM_SET_WIDTYPE(widtype, "conformant");
628 elm_widget_type_set(obj, "conformant");
629 elm_widget_sub_object_add(parent, obj);
630 elm_widget_data_set(obj, wd);
631 elm_widget_del_pre_hook_set(obj, _del_pre_hook);
632 elm_widget_del_hook_set(obj, _del_hook);
633 elm_widget_theme_hook_set(obj, _theme_hook);
634 elm_widget_can_focus_set(obj, EINA_FALSE);
635 elm_widget_content_set_hook_set(obj, _content_set_hook);
636 elm_widget_content_get_hook_set(obj, _content_get_hook);
637 elm_widget_content_unset_hook_set(obj, _content_unset_hook);
639 wd->base = edje_object_add(e);
640 _elm_theme_object_set(obj, wd->base, "conformant", "base", "default");
641 elm_widget_resize_object_set(obj, wd->base);
643 wd->layout = elm_layout_add(obj);
644 edje_object_part_swallow(wd->base, "elm.swallow.content", wd->layout);
645 elm_layout_theme_set(wd->layout, "conformant", "layout", "content");
647 _swallow_conformant_parts(obj);
649 #ifdef HAVE_ELEMENTARY_X
650 Evas_Object *top = elm_widget_top_get(obj);
651 Ecore_X_Window xwin = elm_win_xwindow_get(top);
653 if ((xwin) && (!elm_win_inlined_image_object_get(top)))
655 wd->prop_hdl = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY,
657 wd->vkb_state = ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
659 // FIXME: get kbd region prop
662 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
663 _conformant_move_resize_event_cb, obj);
664 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
665 _conformant_move_resize_event_cb, obj);
666 evas_object_smart_callback_add(wd->layout, "sub-object-del", _sub_del, obj);
669 _mirrored_set(obj, elm_widget_mirrored_get(obj));
675 elm_conformant_content_set(Evas_Object *obj, Evas_Object *content)
677 _content_set_hook(obj, NULL, content);
681 elm_conformant_content_get(const Evas_Object *obj)
683 return _content_get_hook(obj, NULL);
687 elm_conformant_content_unset(Evas_Object *obj)
689 return _content_unset_hook(obj, NULL);
692 EINA_DEPRECATED EAPI Evas_Object *
693 elm_conformant_content_area_get(const Evas_Object *obj)
695 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
696 Widget_Data *wd = elm_widget_data_get(obj);
698 if (!wd) return NULL;
699 /*Finger waggle warning*/
700 _elm_dangerous_call_check(__FUNCTION__);