elementary/panes - content_part_set/get/unset
[framework/uifw/elementary.git] / src / lib / elm_panes.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * TODO
6  * Update the minimun height of the bar in the theme.
7  * No minimun should be set in the vertical theme
8  * Add events (move, start ...)
9  */
10
11 typedef struct _Widget_Data Widget_Data;
12
13 struct _Widget_Data
14 {
15    Evas_Object *panes;
16
17    struct
18      {
19         Evas_Object *left;
20         Evas_Object *right;
21      } contents;
22
23    struct
24      {
25         int x_diff;
26         int y_diff;
27         Eina_Bool move;
28      } move;
29
30    Eina_Bool clicked_double;
31    Eina_Bool horizontal;
32    Eina_Bool fixed;
33 };
34
35 static const char *widtype = NULL;
36 static void _del_hook(Evas_Object *obj);
37 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
38 static void _theme_hook(Evas_Object *obj);
39 static void _sizing_eval(Evas_Object *obj);
40 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
41
42 static const char SIG_CLICKED[] = "clicked";
43 static const char SIG_PRESS[] = "press";
44 static const char SIG_UNPRESS[] = "unpress";
45 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
46
47 static const Evas_Smart_Cb_Description _signals[] = {
48    {SIG_CLICKED, ""},
49    {SIG_PRESS, ""},
50    {SIG_UNPRESS, ""},
51    {SIG_CLICKED_DOUBLE, ""},
52    {NULL, NULL}
53 };
54
55 static void
56 _del_hook(Evas_Object *obj)
57 {
58    Widget_Data *wd = elm_widget_data_get(obj);
59    if (!wd) return;
60    free(wd);
61 }
62
63 static void
64 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
65 {
66    Widget_Data *wd = elm_widget_data_get(obj);
67    if (!wd) return;
68    edje_object_mirrored_set(wd->panes, rtl);
69 }
70
71 static void
72 _theme_hook(Evas_Object *obj)
73 {
74    Widget_Data *wd = elm_widget_data_get(obj);
75    const char *style = elm_widget_style_get(obj);
76    double size;
77
78    if (!wd) return;
79    _elm_widget_mirrored_reload(obj);
80    _mirrored_set(obj, elm_widget_mirrored_get(obj));
81    size = elm_panes_content_left_size_get(obj);
82
83    if (wd->horizontal)
84      _elm_theme_object_set(obj, wd->panes, "panes", "horizontal", style);
85    else
86      _elm_theme_object_set(obj, wd->panes, "panes", "vertical", style);
87
88    if (wd->contents.left)
89      edje_object_part_swallow(wd->panes, "elm.swallow.left", wd->contents.left);
90    if (wd->contents.right)
91      edje_object_part_swallow(wd->panes, "elm.swallow.right", wd->contents.right);
92    if (wd->fixed)
93      edje_object_signal_emit(wd->panes, "elm.panes.fixed", "elm");
94
95    edje_object_scale_set(wd->panes, elm_widget_scale_get(obj) *
96                          _elm_config->scale);
97    _sizing_eval(obj);
98    elm_panes_content_left_size_set(obj, size);
99 }
100
101 static Eina_Bool
102 _elm_panes_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
103 {
104    Widget_Data *wd = elm_widget_data_get(obj);
105    if (!wd) return EINA_FALSE;
106
107    double w, h;
108    edje_object_part_drag_value_get(wd->panes, "elm.bar", &w, &h);
109    if (((wd->horizontal) && ( h == 0.0 )) || ((!wd->horizontal) && ( w == 0.0 )))
110      return elm_widget_focus_next_get(wd->contents.right, dir, next);
111
112    Evas_Object *chain[2];
113
114    /* Direction */
115    if (dir == ELM_FOCUS_PREVIOUS)
116      {
117         chain[0] = wd->contents.right;
118         chain[1] = wd->contents.left;
119      }
120    else if (dir == ELM_FOCUS_NEXT)
121      {
122         chain[0] = wd->contents.left;
123         chain[1] = wd->contents.right;
124      }
125    else
126      return EINA_FALSE;
127
128    unsigned char i = elm_widget_focus_get(chain[1]);
129
130    if (elm_widget_focus_next_get(chain[i], dir, next))
131      return EINA_TRUE;
132
133    i = !i;
134
135    Evas_Object *to_focus;
136    if (elm_widget_focus_next_get(chain[i], dir, &to_focus))
137      {
138         *next = to_focus;
139         return !!i;
140      }
141
142    return EINA_FALSE;
143 }
144
145 static void
146 _sizing_eval(Evas_Object *obj)
147 {
148    Widget_Data *wd = elm_widget_data_get(obj);
149    if (!wd) return;
150 }
151
152 static void
153 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
154 {
155    _sizing_eval(data);
156 }
157
158 static void
159 _sub_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
160 {
161    Widget_Data *wd = elm_widget_data_get(obj);
162    Evas_Object *sub = event_info;
163
164    if (!wd) return;
165    if (sub == wd->contents.left)
166      {
167         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
168                                             _changed_size_hints, obj);
169         wd->contents.left = NULL;
170         _sizing_eval(obj);
171      }
172    else if (sub == wd->contents.right)
173      {
174         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
175                                             _changed_size_hints, obj);
176         wd->contents.right= NULL;
177         _sizing_eval(obj);
178      }
179 }
180
181
182 static void
183 _clicked(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
184 {
185    evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
186 }
187
188 static void
189 _clicked_double(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
190 {
191    Widget_Data *wd = elm_widget_data_get(data);
192
193    wd->clicked_double = EINA_TRUE;
194 }
195
196 static void
197 _press(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
198 {
199    evas_object_smart_callback_call(data, SIG_PRESS, NULL);
200 }
201
202 static void
203 _unpress(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
204 {
205    Widget_Data *wd = elm_widget_data_get(data);
206    evas_object_smart_callback_call(data, SIG_UNPRESS, NULL);
207
208    if (wd->clicked_double)
209      {
210         evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, NULL);
211         wd->clicked_double = EINA_FALSE;
212      }
213 }
214
215 static void
216 _content_left_set(Evas_Object *obj, Evas_Object *content)
217 {
218    Widget_Data *wd = elm_widget_data_get(obj);
219    if (wd->contents.left)
220      {
221         evas_object_del(wd->contents.left);
222         wd->contents.left = NULL;
223      }
224    if (content)
225      {
226         wd->contents.left = content;
227         elm_widget_sub_object_add(obj, content);
228         edje_object_part_swallow(wd->panes, "elm.swallow.left", content);
229      }
230 }
231
232 static void
233 _content_right_set(Evas_Object *obj, Evas_Object *content)
234 {
235    Widget_Data *wd = elm_widget_data_get(obj);
236    if (wd->contents.right)
237      {
238         evas_object_del(wd->contents.right);
239         wd->contents.right = NULL;
240      }
241    if (content)
242      {
243         wd->contents.right = content;
244         elm_widget_sub_object_add(obj, content);
245         edje_object_part_swallow(wd->panes, "elm.swallow.right", content);
246      }
247 }
248
249 static Evas_Object *
250 _content_left_unset(Evas_Object *obj)
251 {
252    Widget_Data *wd = elm_widget_data_get(obj);
253    if (!wd->contents.left) return NULL;
254    Evas_Object *content = wd->contents.left;
255    elm_widget_sub_object_del(obj, content);
256    edje_object_part_unswallow(wd->panes, content);
257    wd->contents.left = NULL;
258    return content;
259 }
260
261 static Evas_Object *
262 _content_right_unset(Evas_Object *obj)
263 {
264    Widget_Data *wd = elm_widget_data_get(obj);
265    if (!wd->contents.right) return NULL;
266    Evas_Object *content = wd->contents.right;
267    elm_widget_sub_object_del(obj, content);
268    edje_object_part_unswallow(wd->panes, content);
269    wd->contents.right = NULL;
270    return content;
271 }
272
273 static void
274 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
275 {
276    ELM_CHECK_WIDTYPE(obj, widtype);
277    Widget_Data *wd = elm_widget_data_get(obj);
278    if (!wd) return;
279
280    if ((!part) || (!strcmp(part, "elm.swallow.right")))
281      _content_right_set(obj, content);
282    else if(!strcmp(part, "elm.swallow.left"))
283      _content_left_set(obj, content);
284 }
285
286 static Evas_Object *
287 _content_get_hook(const Evas_Object *obj, const char *part)
288 {
289    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
290    Widget_Data *wd = elm_widget_data_get(obj);
291    if (!wd) return NULL;
292    if ((!part) || (!strcmp(part, "elm.swallow.right")))
293      return wd->contents.left;
294    else if (!strcmp(part, "elm.swallow.left"))
295      return wd->contents.right;
296    return NULL;
297 }
298
299 static Evas_Object *
300 _content_unset_hook(Evas_Object *obj, const char *part)
301 {
302    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
303    Widget_Data *wd = elm_widget_data_get(obj);
304    if (!wd) return NULL;
305
306    if ((!part) || (!strcmp(part, "elm.swallow.right")))
307      _content_right_unset(obj);
308    else if (!strcmp(part, "elm.swallow.left"))
309      _content_left_unset(obj);
310
311    return NULL;
312 }
313
314 EAPI Evas_Object *
315 elm_panes_add(Evas_Object *parent)
316 {
317    Evas_Object *obj;
318    Evas *e;
319    Widget_Data *wd;
320
321    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
322
323    ELM_SET_WIDTYPE(widtype, "panes");
324    elm_widget_type_set(obj, "panes");
325    elm_widget_sub_object_add(parent, obj);
326    elm_widget_data_set(obj, wd);
327    elm_widget_del_hook_set(obj, _del_hook);
328    elm_widget_theme_hook_set(obj, _theme_hook);
329    elm_widget_focus_next_hook_set(obj, _elm_panes_focus_next_hook);
330    elm_widget_content_set_hook_set(obj, _content_set_hook);
331    elm_widget_content_get_hook_set(obj, _content_get_hook);
332    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
333    elm_widget_can_focus_set(obj, EINA_FALSE);
334
335    wd->panes = edje_object_add(e);
336    _elm_theme_object_set(obj, wd->panes, "panes", "vertical", "default");
337    elm_widget_resize_object_set(obj, wd->panes);
338    evas_object_show(wd->panes);
339
340    elm_panes_content_left_size_set(obj, 0.5);
341
342    edje_object_signal_callback_add(wd->panes, "elm,action,click", "",
343                                    _clicked, obj);
344    edje_object_signal_callback_add(wd->panes, "elm,action,click,double", "",
345                                    _clicked_double, obj);
346    edje_object_signal_callback_add(wd->panes, "elm,action,press", "",
347                                    _press, obj);
348    edje_object_signal_callback_add(wd->panes, "elm,action,unpress", "",
349                                    _unpress, obj);
350
351    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
352    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
353                                   _changed_size_hints, obj);
354
355    evas_object_smart_callbacks_descriptions_set(obj, _signals);
356
357    _mirrored_set(obj, elm_widget_mirrored_get(obj));
358    _sizing_eval(obj);
359    return obj;
360 }
361
362 EAPI void
363 elm_panes_content_left_set(Evas_Object *obj, Evas_Object *content)
364 {
365    _content_set_hook(obj, "elm.swallow.left", content);
366 }
367
368 EAPI void
369 elm_panes_content_right_set(Evas_Object *obj, Evas_Object *content)
370 {
371    _content_set_hook(obj, NULL, content);
372 }
373
374 EAPI Evas_Object *
375 elm_panes_content_left_get(const Evas_Object *obj)
376 {
377    return _content_get_hook(obj, "elm.swallow.left");
378 }
379
380 EAPI Evas_Object *
381 elm_panes_content_right_get(const Evas_Object *obj)
382 {
383    return _content_get_hook(obj, NULL);
384 }
385
386 EAPI Evas_Object *
387 elm_panes_content_left_unset(Evas_Object *obj)
388 {
389    return _content_unset_hook(obj, "elm.swallow.left");
390 }
391
392 EAPI Evas_Object *
393 elm_panes_content_right_unset(Evas_Object *obj)
394 {
395    return _content_unset_hook(obj, "elm.swallow.right");
396 }
397
398 EAPI double
399 elm_panes_content_left_size_get(const Evas_Object *obj)
400 {
401    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
402    Widget_Data *wd = elm_widget_data_get(obj);
403    double w, h;
404
405    if (!wd) return 0;
406    edje_object_part_drag_value_get(wd->panes, "elm.bar", &w, &h);
407    if (wd->horizontal) return h;
408    else return w;
409 }
410
411 EAPI void
412 elm_panes_content_left_size_set(Evas_Object *obj, double size)
413 {
414    ELM_CHECK_WIDTYPE(obj, widtype);
415    Widget_Data *wd = elm_widget_data_get(obj);
416    if (!wd) return;
417    if (size < 0.0) size = 0.0;
418    else if (size > 1.0) size = 1.0;
419    if (wd->horizontal)
420      edje_object_part_drag_value_set(wd->panes, "elm.bar", 0.0, size);
421    else
422      edje_object_part_drag_value_set(wd->panes, "elm.bar", size, 0.0);
423 }
424
425 EAPI void
426 elm_panes_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
427 {
428    ELM_CHECK_WIDTYPE(obj, widtype);
429    Widget_Data *wd = elm_widget_data_get(obj);
430    if (!wd) return;
431    wd->horizontal = horizontal;
432    _theme_hook(obj);
433    elm_panes_content_left_size_set(obj, 0.5);
434 }
435
436 EAPI Eina_Bool
437 elm_panes_horizontal_get(const Evas_Object *obj)
438 {
439    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
440    Widget_Data *wd = elm_widget_data_get(obj);
441    if (!wd) return EINA_FALSE;
442    return wd->horizontal;
443 }
444
445 EAPI void
446 elm_panes_fixed_set(Evas_Object *obj, Eina_Bool fixed)
447 {
448    ELM_CHECK_WIDTYPE(obj, widtype);
449    Widget_Data *wd = elm_widget_data_get(obj);
450    if (!wd) return;
451    wd->fixed = !!fixed;
452    if (wd->fixed == EINA_TRUE)
453      edje_object_signal_emit(wd->panes, "elm.panes.fixed", "elm");
454    else
455      edje_object_signal_emit(wd->panes, "elm.panes.unfixed", "elm");
456 }
457
458 EAPI Eina_Bool
459 elm_panes_fixed_get(const Evas_Object *obj)
460 {
461    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
462    Widget_Data *wd = elm_widget_data_get(obj);
463    if (!wd) return EINA_FALSE;
464    return wd->fixed;
465 }