elementary/panes - added exception handlings
[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 EAPI Evas_Object *
216 elm_panes_add(Evas_Object *parent)
217 {
218    Evas_Object *obj;
219    Evas *e;
220    Widget_Data *wd;
221
222    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
223
224    ELM_SET_WIDTYPE(widtype, "panes");
225    elm_widget_type_set(obj, "panes");
226    elm_widget_sub_object_add(parent, obj);
227    elm_widget_data_set(obj, wd);
228    elm_widget_del_hook_set(obj, _del_hook);
229    elm_widget_theme_hook_set(obj, _theme_hook);
230    elm_widget_focus_next_hook_set(obj, _elm_panes_focus_next_hook);
231    elm_widget_can_focus_set(obj, EINA_FALSE);
232
233    wd->panes = edje_object_add(e);
234    _elm_theme_object_set(obj, wd->panes, "panes", "vertical", "default");
235    elm_widget_resize_object_set(obj, wd->panes);
236    evas_object_show(wd->panes);
237
238    elm_panes_content_left_size_set(obj, 0.5);
239
240    edje_object_signal_callback_add(wd->panes, "elm,action,click", "",
241                                    _clicked, obj);
242    edje_object_signal_callback_add(wd->panes, "elm,action,click,double", "",
243                                    _clicked_double, obj);
244    edje_object_signal_callback_add(wd->panes, "elm,action,press", "",
245                                    _press, obj);
246    edje_object_signal_callback_add(wd->panes, "elm,action,unpress", "",
247                                    _unpress, obj);
248
249    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
250    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
251                                   _changed_size_hints, obj);
252
253    evas_object_smart_callbacks_descriptions_set(obj, _signals);
254
255    _mirrored_set(obj, elm_widget_mirrored_get(obj));
256    _sizing_eval(obj);
257    return obj;
258 }
259
260
261 EAPI void
262 elm_panes_content_left_set(Evas_Object *obj, Evas_Object *content)
263 {
264    ELM_CHECK_WIDTYPE(obj, widtype);
265    Widget_Data *wd = elm_widget_data_get(obj);
266    if (!wd) return;
267    if (wd->contents.left)
268      {
269         evas_object_del(wd->contents.left);
270         wd->contents.left = NULL;
271      }
272    if (content)
273      {
274         wd->contents.left = content;
275         elm_widget_sub_object_add(obj, content);
276         edje_object_part_swallow(wd->panes, "elm.swallow.left", content);
277      }
278 }
279
280 EAPI void
281 elm_panes_content_right_set(Evas_Object *obj, Evas_Object *content)
282 {
283    ELM_CHECK_WIDTYPE(obj, widtype);
284    Widget_Data *wd = elm_widget_data_get(obj);
285    if (!wd) return;
286    if (wd->contents.right)
287      {
288         evas_object_del(wd->contents.right);
289         wd->contents.right = NULL;
290      }
291    if (content)
292      {
293         wd->contents.right = content;
294         elm_widget_sub_object_add(obj, content);
295         edje_object_part_swallow(wd->panes, "elm.swallow.right", content);
296      }
297 }
298
299 EAPI Evas_Object *
300 elm_panes_content_left_get(const Evas_Object *obj)
301 {
302    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
303    Widget_Data *wd = elm_widget_data_get(obj);
304    if (!wd) return NULL;
305    return wd->contents.left;
306 }
307
308 EAPI Evas_Object *
309 elm_panes_content_right_get(const Evas_Object *obj)
310 {
311    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
312    Widget_Data *wd = elm_widget_data_get(obj);
313    return wd->contents.right;
314 }
315
316 EAPI Evas_Object *
317 elm_panes_content_left_unset(Evas_Object *obj)
318 {
319    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
320    Widget_Data *wd = elm_widget_data_get(obj);
321    if (!wd) return NULL;
322    if (!wd->contents.left) return NULL;
323    Evas_Object *content = wd->contents.left;
324    elm_widget_sub_object_del(obj, content);
325    edje_object_part_unswallow(wd->panes, content);
326    wd->contents.left = NULL;
327    return content;
328 }
329
330 EAPI Evas_Object *
331 elm_panes_content_right_unset(Evas_Object *obj)
332 {
333    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
334    Widget_Data *wd = elm_widget_data_get(obj);
335    if (!wd) return NULL;
336    if (!wd->contents.right) return NULL;
337    Evas_Object *content = wd->contents.right;
338    elm_widget_sub_object_del(obj, content);
339    edje_object_part_unswallow(wd->panes, content);
340    wd->contents.right = NULL;
341    return content;
342 }
343
344 EAPI double
345 elm_panes_content_left_size_get(const Evas_Object *obj)
346 {
347    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
348    Widget_Data *wd = elm_widget_data_get(obj);
349    double w, h;
350
351    if (!wd) return 0;
352    edje_object_part_drag_value_get(wd->panes, "elm.bar", &w, &h);
353    if (wd->horizontal) return h;
354    else return w;
355 }
356
357 EAPI void
358 elm_panes_content_left_size_set(Evas_Object *obj, double size)
359 {
360    ELM_CHECK_WIDTYPE(obj, widtype);
361    Widget_Data *wd = elm_widget_data_get(obj);
362    if (!wd) return;
363    if (size < 0.0) size = 0.0;
364    else if (size > 1.0) size = 1.0;
365    if (wd->horizontal)
366      edje_object_part_drag_value_set(wd->panes, "elm.bar", 0.0, size);
367    else
368      edje_object_part_drag_value_set(wd->panes, "elm.bar", size, 0.0);
369 }
370
371 EAPI void
372 elm_panes_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
373 {
374    ELM_CHECK_WIDTYPE(obj, widtype);
375    Widget_Data *wd = elm_widget_data_get(obj);
376    if (!wd) return;
377    wd->horizontal = horizontal;
378    _theme_hook(obj);
379    elm_panes_content_left_size_set(obj, 0.5);
380 }
381
382 EAPI Eina_Bool
383 elm_panes_horizontal_get(const Evas_Object *obj)
384 {
385    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
386    Widget_Data *wd = elm_widget_data_get(obj);
387    if (!wd) return EINA_FALSE;
388    return wd->horizontal;
389 }
390
391 EAPI void
392 elm_panes_fixed_set(Evas_Object *obj, Eina_Bool fixed)
393 {
394    ELM_CHECK_WIDTYPE(obj, widtype);
395    Widget_Data *wd = elm_widget_data_get(obj);
396    if (!wd) return;
397    wd->fixed = !!fixed;
398    if (wd->fixed == EINA_TRUE)
399      edje_object_signal_emit(wd->panes, "elm.panes.fixed", "elm");
400    else
401      edje_object_signal_emit(wd->panes, "elm.panes.unfixed", "elm");
402 }
403
404 EAPI Eina_Bool
405 elm_panes_fixed_get(const Evas_Object *obj)
406 {
407    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
408    Widget_Data *wd = elm_widget_data_get(obj);
409    if (!wd) return EINA_FALSE;
410    return wd->fixed;
411 }