641fdb8f3611291e42d281e4aef782fca47ed247
[framework/uifw/elementary.git] / src / lib / elm_conform.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Conformant Conformant
6  * @ingroup Elementary
7  * 
8  * The aim is to provide a widget that can be used in elementary apps to 
9  * account for space taken up by the indicator & softkey windows when running 
10  * the illume2 module of E17.
11  */
12
13 typedef struct _Widget_Data Widget_Data;
14 struct _Widget_Data
15 {
16    Evas_Object *base;
17    Evas_Object *shelf, *panel, *virtualkeypad;
18    Evas_Object *content;
19    Evas_Object *scroller;
20    Ecore_Event_Handler *prop_hdl;
21 #ifdef HAVE_ELEMENTARY_X
22    Ecore_X_Virtual_Keyboard_State vkb_state;
23 #endif
24 };
25
26 /* local function prototypes */
27 static const char *widtype = NULL;
28 static void
29 _del_hook(Evas_Object *obj);
30 static void
31 _theme_hook(Evas_Object *obj);
32 static void
33 _swallow_conformant_parts(Evas_Object *obj);
34 static void
35 _sizing_eval(Evas_Object *obj);
36 static Eina_Bool
37 _prop_change(void *data, int type, void *event);
38
39 /* local functions */
40 static void
41 _del_hook(Evas_Object *obj)
42 {
43    Widget_Data *wd = elm_widget_data_get(obj);
44    if (!wd) return;
45    if (wd->prop_hdl) ecore_event_handler_del(wd->prop_hdl);
46    if (wd->shelf) evas_object_del(wd->shelf);
47    if (wd->virtualkeypad) evas_object_del(wd->virtualkeypad);
48    if (wd->panel) evas_object_del(wd->panel);
49    free(wd);
50 }
51
52 static void
53 _theme_hook(Evas_Object *obj)
54 {
55    Widget_Data *wd = elm_widget_data_get(obj);
56    if (!wd) return;
57    _elm_theme_object_set(obj, wd->base, "conformant", "base",
58                          elm_widget_style_get(obj));
59    _swallow_conformant_parts(obj);
60
61    if (wd->content) edje_object_part_swallow(wd->base, "elm.swallow.content",
62                                              wd->content);
63    edje_object_scale_set(wd->base, elm_widget_scale_get(obj)
64             * _elm_config->scale);
65    _sizing_eval(obj);
66 }
67
68 static void
69 _sizing_eval(Evas_Object *obj)
70 {
71    Widget_Data *wd = elm_widget_data_get(obj);
72    Evas_Coord mw = -1, mh = -1;
73    if (!wd) return;
74    edje_object_size_min_calc(wd->base, &mw, &mh);
75    evas_object_size_hint_min_set(obj, mw, mh);
76    evas_object_size_hint_max_set(obj, -1, -1);
77 }
78
79 static void
80 _swallow_conformant_parts(Evas_Object *obj)
81 {
82    Widget_Data *wd = elm_widget_data_get(obj);
83
84    int sh = -1;
85 #ifdef HAVE_ELEMENTARY_X
86    Ecore_X_Window zone, xwin;
87
88    xwin = elm_win_xwindow_get(obj);
89    zone = ecore_x_e_illume_zone_get(xwin);
90
91    ecore_x_e_illume_indicator_geometry_get(zone, NULL, NULL, NULL, &sh);
92 #endif
93    if (sh < 0) sh = 0;
94    if (!wd->shelf)
95       wd->shelf = evas_object_rectangle_add(evas_object_evas_get(obj));
96    evas_object_color_set(wd->shelf, 0, 0, 0, 0);
97    evas_object_size_hint_min_set(wd->shelf, -1, sh);
98    evas_object_size_hint_max_set(wd->shelf, -1, sh);
99    edje_object_part_swallow(wd->base, "elm.swallow.shelf", wd->shelf);
100
101    wd->scroller = NULL;
102    sh = -1;
103 #ifdef HAVE_ELEMENTARY_X
104    ecore_x_e_illume_keyboard_geometry_get(zone, NULL, NULL, NULL, &sh);
105 #endif
106    if (sh < 0) sh = 0;
107    if (!wd->virtualkeypad)
108       wd->virtualkeypad = evas_object_rectangle_add(evas_object_evas_get(obj));
109    evas_object_color_set(wd->virtualkeypad, 0, 0, 0, 0);
110    evas_object_size_hint_min_set(wd->virtualkeypad, -1, sh);
111    evas_object_size_hint_max_set(wd->virtualkeypad, -1, sh);
112    edje_object_part_swallow(wd->base, "elm.swallow.virtualkeypad",
113                             wd->virtualkeypad);
114
115    sh = -1;
116 #ifdef HAVE_ELEMENTARY_X
117    ecore_x_e_illume_softkey_geometry_get(zone, NULL, NULL, NULL, &sh);
118 #endif
119    if (sh < 0) sh = 0;
120    if (!wd->panel)
121       wd->panel = evas_object_rectangle_add(evas_object_evas_get(obj));
122    evas_object_color_set(wd->panel, 0, 0, 0, 0);
123    evas_object_size_hint_min_set(wd->panel, -1, sh);
124    evas_object_size_hint_max_set(wd->panel, -1, sh);
125    edje_object_part_swallow(wd->base, "elm.swallow.panel", wd->panel);
126 }
127
128 static void
129 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
130 {
131    Widget_Data *wd = elm_widget_data_get(data);
132    if (!wd) return;
133    _sizing_eval(data);
134 }
135
136 static void
137 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
138 {
139    Widget_Data *wd = elm_widget_data_get(obj);
140    Evas_Object *sub = event_info;
141    if (!wd) return;
142    if (sub == wd->content)
143    {
144       evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
145                _changed_size_hints, obj);
146       wd->content = NULL;
147       _sizing_eval(obj);
148    }
149 }
150
151 static void
152 _content_resize_event_cb(void *data, Evas *e, Evas_Object *obj,
153                          void *event_info)
154 {
155    Evas_Object *focus_obj;
156    Widget_Data *wd = elm_widget_data_get(obj);
157    if (wd->vkb_state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF) return;
158    focus_obj = elm_widget_focused_object_get(obj);
159    if (focus_obj)
160    {
161       Evas_Coord x, y, w, h;
162
163       elm_widget_show_region_get(focus_obj, &x, &y, &w, &h);
164
165       if (h < _elm_config->finger_size)
166          h = _elm_config->finger_size;
167       else
168          h = 1 + h; //elm_widget_show_region_set expects some change, to redo the job.
169       elm_widget_show_region_set(focus_obj, x, y, w, h);
170    }
171 }
172
173 static void
174 _update_autoscroll_objs(void *data)
175 {
176    char *type;
177    Evas_Object *sub, *top_scroller = NULL;
178    Evas_Object *conformant = (Evas_Object *) data;
179    Widget_Data *wd = elm_widget_data_get(data);
180    if (!wd) return;
181    sub = elm_widget_focused_object_get(conformant);
182
183    //Look up for Top most scroller in the Focus Object hierarchy inside Conformant.
184    while (sub)
185    {
186       type = elm_widget_type_get(sub);
187       if (!strcmp(type, "conformant")) break;
188       if (!strcmp(type, "scroller") || !strcmp(type, "genlist"))
189          top_scroller = sub;
190
191       sub = elm_object_parent_widget_get(sub);
192    }
193
194    //If the scroller got changed by app, replace it.
195    if (top_scroller != wd->scroller)
196    {
197       if (wd->scroller) evas_object_event_callback_del(wd->scroller,
198                                                        EVAS_CALLBACK_RESIZE,
199                                                        _content_resize_event_cb);
200       wd->scroller = top_scroller;
201       if (wd->scroller) evas_object_event_callback_add(wd->scroller,
202                                                        EVAS_CALLBACK_RESIZE,
203                                                        _content_resize_event_cb,
204                                                        data);
205    }
206 }
207
208 static Eina_Bool
209 _prop_change(void *data, int type __UNUSED__, void *event)
210 {
211 #ifdef HAVE_ELEMENTARY_X
212    int indicator_height=0;
213    Ecore_X_Virtual_Keyboard_State virt_keypad_state = ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN;
214    Ecore_X_Event_Window_Property *ev;
215    Widget_Data *wd = elm_widget_data_get(data);
216    if (!wd) return ECORE_CALLBACK_PASS_ON;
217    ev = event;
218    if (ev->atom == ECORE_X_ATOM_E_ILLUME_ZONE)
219    {
220       Ecore_X_Window zone;
221       int sh = -1;
222
223       zone = ecore_x_e_illume_zone_get(ev->win);
224       ecore_x_e_illume_indicator_geometry_get(zone, NULL, NULL, NULL, &sh);
225       if (sh < 0) sh = indicator_height;
226
227       evas_object_size_hint_min_set(wd->shelf, -1, sh);
228       evas_object_size_hint_max_set(wd->shelf, -1, sh);
229       sh = -1;
230       zone = ecore_x_e_illume_zone_get(ev->win);
231       ecore_x_e_illume_keyboard_geometry_get(zone, NULL, NULL, NULL, &sh);
232       if (sh < 0) sh = 0;
233       evas_object_size_hint_min_set(wd->virtualkeypad, -1, sh);
234       evas_object_size_hint_max_set(wd->virtualkeypad, -1, sh);
235       sh = -1;
236       ecore_x_e_illume_softkey_geometry_get(zone, NULL, NULL, NULL, &sh);
237       if (sh < 0) sh = 0;
238       evas_object_size_hint_min_set(wd->panel, -1, sh);
239       evas_object_size_hint_max_set(wd->panel, -1, sh);
240    }
241    else if (ev->atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY)
242    {
243       Ecore_X_Window zone;
244       int sh = -1;
245
246       zone = ecore_x_e_illume_zone_get(ev->win);
247       ecore_x_e_illume_indicator_geometry_get(zone, NULL, NULL, NULL, &sh);
248       if (sh < 0) sh = 0;
249       evas_object_size_hint_min_set(wd->shelf, -1, sh);
250       evas_object_size_hint_max_set(wd->shelf, -1, sh);
251    }
252    else if (ev->atom == ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY)
253    {
254       Ecore_X_Window zone;
255       int sh = -1;
256
257       zone = ecore_x_e_illume_zone_get(ev->win);
258       ecore_x_e_illume_softkey_geometry_get(zone, NULL, NULL, NULL, &sh);
259       if (sh < 0) sh = 0;
260       evas_object_size_hint_min_set(wd->panel, -1, sh);
261       evas_object_size_hint_max_set(wd->panel, -1, sh);
262    }
263    else if (ev->atom == ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY)
264    {
265       Ecore_X_Window zone;
266       int ky = -1, kh = -1;
267
268       zone = ecore_x_e_illume_zone_get(ev->win);
269       ecore_x_e_illume_keyboard_geometry_get(zone, NULL, &ky, NULL, &kh);
270       if (kh < 0) kh = 0;
271       evas_object_size_hint_min_set(wd->virtualkeypad, -1, kh);
272       evas_object_size_hint_max_set(wd->virtualkeypad, -1, kh);
273    }
274    else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
275    {
276       Ecore_X_Window zone;
277       zone = ecore_x_e_illume_zone_get(ev->win);
278       wd->vkb_state = ecore_x_e_virtual_keyboard_state_get(zone);
279
280       if(wd->vkb_state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
281       {
282          evas_object_size_hint_min_set(wd->virtualkeypad, -1, 0);
283          evas_object_size_hint_max_set(wd->virtualkeypad, -1, 0);
284       }
285       else
286       _update_autoscroll_objs(data);
287    }
288 #endif
289
290    return ECORE_CALLBACK_PASS_ON;
291 }
292
293 /**
294  * Add a new Conformant object
295  * 
296  * @param parent The parent object
297  * @return The new conformant object or NULL if it cannot be created
298  * 
299  * @ingroup Conformant
300  */
301 EAPI Evas_Object *
302 elm_conformant_add(Evas_Object *parent)
303 {
304    Evas_Object *obj;
305    Evas *evas;
306    Widget_Data *wd;
307
308    wd = ELM_NEW(Widget_Data);
309
310    evas = evas_object_evas_get(parent);
311
312    obj = elm_widget_add(evas);
313    ELM_SET_WIDTYPE(widtype, "conformant");
314    elm_widget_type_set(obj, "conformant");
315    elm_widget_sub_object_add(parent, obj);
316    elm_widget_data_set(obj, wd);
317    elm_widget_del_hook_set(obj, _del_hook);
318    elm_widget_theme_hook_set(obj, _theme_hook);
319
320    wd->base = edje_object_add(evas);
321    _elm_theme_object_set(obj, wd->base, "conformant", "base", "default");
322    elm_widget_resize_object_set(obj, wd->base);
323    _swallow_conformant_parts(obj);
324
325 #ifdef HAVE_ELEMENTARY_X
326    wd->prop_hdl = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY,
327             _prop_change, obj);
328    wd->vkb_state = ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
329 #endif
330
331    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
332
333    _sizing_eval(obj);
334    return obj;
335 }
336
337 /**
338  * Set the content of the conformant widget
339  *
340  * Once the content object is set, a previously set one will be deleted.
341  * If you want to keep that old content object, use the
342  * elm_conformat_content_unset() function.
343  *
344  * @param obj The conformant object
345  * @return The content that was being used
346  *
347  * @ingroup Conformant
348  */
349 EAPI void
350 elm_conformant_content_set(Evas_Object *obj, Evas_Object *content)
351 {
352    ELM_CHECK_WIDTYPE(obj, widtype);
353    Widget_Data *wd = elm_widget_data_get(obj);
354    if (!wd) return;
355    if (wd->content == content) return;
356    if (wd->content) evas_object_del(wd->content);
357    wd->content = content;
358    if (content)
359    {
360       elm_widget_sub_object_add(obj, content);
361       evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
362                                      _changed_size_hints, obj);
363       edje_object_part_swallow(wd->base, "elm.swallow.content", content);
364    }
365    _sizing_eval(obj);
366 }
367
368 /**
369  * Unset the content of the conformant widget
370  *
371  * Unparent and return the content object which was set for this widget;
372  *
373  * @param obj The conformant object
374  * @return The content that was being used
375  *
376  * @ingroup Conformant
377  */
378 EAPI Evas_Object *
379 elm_conformant_content_unset(Evas_Object *obj)
380 {
381    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
382    Widget_Data *wd = elm_widget_data_get(obj);
383    Evas_Object *content;
384    if (!wd) return NULL;
385    if (!wd->content) return NULL;
386    content = wd->content;
387    elm_widget_sub_object_del(obj, wd->content);
388    edje_object_part_unswallow(wd->base, wd->content);
389    wd->content = NULL;
390    return content;
391 }