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