Merge "[Password]: New design based changes, a new style removed password mode contro...
[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  * @ingroup Elementary
7  *
8  */
9
10 typedef struct _Widget_Data Widget_Data;
11
12 struct _Widget_Data
13 {
14    Evas_Object *panes;
15
16    struct
17      {
18         Evas_Object *left;
19         Evas_Object *right;
20      } contents;
21
22    struct
23      {
24         int x_diff;
25         int y_diff;
26         Eina_Bool move;
27      } move;
28
29    Eina_Bool clicked_double;
30    Eina_Bool horizontal;
31    Eina_Bool fixed;
32 };
33
34 static const char *widtype = NULL;
35 static void _del_hook(Evas_Object *obj);
36 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
37 static void _theme_hook(Evas_Object *obj);
38 static void _sizing_eval(Evas_Object *obj);
39 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
40
41 static void
42 _del_hook(Evas_Object *obj)
43 {
44    Widget_Data *wd = elm_widget_data_get(obj);
45    if (!wd) return;
46    if (wd->panes) evas_object_del(wd->panes);
47    free(wd);
48 }
49
50 static void
51 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
52 {
53    Widget_Data *wd = elm_widget_data_get(obj);
54    if (!wd) return;
55    edje_object_mirrored_set(wd->panes, rtl);
56 }
57
58 static void
59 _theme_hook(Evas_Object *obj)
60 {
61    Widget_Data *wd = elm_widget_data_get(obj);
62    const char *style = elm_widget_style_get(obj);
63    double size;
64
65    if (!wd) return;
66    _elm_widget_mirrored_reload(obj);
67    _mirrored_set(obj, elm_widget_mirrored_get(obj));
68    size = elm_panes_content_left_size_get(obj);
69
70    if (wd->horizontal)
71      _elm_theme_object_set(obj, wd->panes, "panes", "horizontal", style);
72    else
73      _elm_theme_object_set(obj, wd->panes, "panes", "vertical", style);
74
75    if (wd->contents.left)
76      edje_object_part_swallow(wd->panes, "elm.swallow.left", wd->contents.left);
77    if (wd->contents.right)
78      edje_object_part_swallow(wd->panes, "elm.swallow.right", wd->contents.right);
79    if(wd->contents.left && wd->contents.right)
80      edje_object_signal_emit(wd->panes, "elm.panes.pair", "elm");
81    if(wd->fixed)
82            edje_object_signal_emit(wd->panes, "elm.panes.fixed", "elm");
83    edje_object_scale_set(wd->panes, elm_widget_scale_get(obj) *
84                          _elm_config->scale);
85    _sizing_eval(obj);
86    elm_panes_content_left_size_set(obj, size);
87 }
88
89 static Eina_Bool
90 _elm_panes_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
91 {
92    Widget_Data *wd = elm_widget_data_get(obj);
93
94    if (!wd)
95      return EINA_FALSE;
96
97    double w, h;
98    edje_object_part_drag_value_get(wd->panes, "elm.bar", &w, &h);
99    if (((wd->horizontal) && ( h == 0.0 )) || ((!wd->horizontal) && ( w == 0.0 )))
100      return elm_widget_focus_next_get(wd->contents.right, dir, next);
101
102    Evas_Object *chain[2];
103
104    /* Direction */
105    if (dir == ELM_FOCUS_PREVIOUS)
106      {
107         chain[0] = wd->contents.right;
108         chain[1] = wd->contents.left;
109      }
110    else if (dir == ELM_FOCUS_NEXT)
111      {
112         chain[0] = wd->contents.left;
113         chain[1] = wd->contents.right;
114      }
115    else
116      return EINA_FALSE;
117
118    unsigned char i = elm_widget_focus_get(chain[1]);
119
120    if (elm_widget_focus_next_get(chain[i], dir, next))
121      return EINA_TRUE;
122
123    i = !i;
124
125    Evas_Object *to_focus;
126    if (elm_widget_focus_next_get(chain[i], dir, &to_focus))
127      {
128         *next = to_focus;
129         return !!i;
130      }
131
132    return EINA_FALSE;
133 }
134
135 static void
136 _sizing_eval(Evas_Object *obj)
137 {
138    Widget_Data *wd = elm_widget_data_get(obj);
139    if (!wd) return;
140 }
141
142 static void
143 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
144 {
145    _sizing_eval(data);
146 }
147
148 static void
149 _sub_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
150 {
151    Widget_Data *wd = elm_widget_data_get(obj);
152    Evas_Object *sub = event_info;
153
154    if (!wd) return;
155    if (sub == wd->contents.left)
156      {
157         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
158                                             _changed_size_hints, obj);
159         wd->contents.left = NULL;
160         _sizing_eval(obj);
161      }
162    else if (sub == wd->contents.right)
163      {
164         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
165                                             _changed_size_hints, obj);
166         wd->contents.right= NULL;
167         _sizing_eval(obj);
168      }
169 }
170
171 static void
172 _clicked(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
173 {
174    evas_object_smart_callback_call(data, "clicked", NULL);
175 }
176
177 static void
178 _clicked_double(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
179 {
180    Widget_Data *wd = elm_widget_data_get(data);
181
182    wd->clicked_double = EINA_TRUE;
183 }
184
185 static void
186 _press(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
187 {
188    evas_object_smart_callback_call(data, "press", NULL);
189 }
190
191 static void
192 _unpress(void *data, Evas_Object *obj __UNUSED__ , const char *emission __UNUSED__, const char *source __UNUSED__)
193 {
194    Widget_Data *wd = elm_widget_data_get(data);
195    evas_object_smart_callback_call(data, "unpress", NULL);
196
197    if (wd->clicked_double)
198      {
199         evas_object_smart_callback_call(data, "clicked,double", NULL);
200         wd->clicked_double = EINA_FALSE;
201      }
202 }
203
204 /**
205  * Add a new panes to the parent
206  *
207  * @param[in] parent The parent object
208  * @return The new object or NULL if it cannot be created
209  *
210  * @ingroup Panes
211  */
212 EAPI Evas_Object *
213 elm_panes_add(Evas_Object *parent)
214 {
215    Evas_Object *obj;
216    Evas *e;
217    Widget_Data *wd;
218
219    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
220
221    ELM_SET_WIDTYPE(widtype, "panes");
222    elm_widget_type_set(obj, "panes");
223    elm_widget_can_focus_set(obj, EINA_FALSE);
224    elm_widget_sub_object_add(parent, obj);
225    elm_widget_data_set(obj, wd);
226    elm_widget_del_hook_set(obj, _del_hook);
227    elm_widget_theme_hook_set(obj, _theme_hook);
228    elm_widget_focus_next_hook_set(obj, _elm_panes_focus_next_hook);
229    wd->contents.left = NULL;
230    wd->contents.right = NULL;
231
232    wd->panes = edje_object_add(e);
233    _elm_theme_object_set(obj, wd->panes, "panes", "vertical", "default");
234    elm_widget_resize_object_set(obj, wd->panes);
235    evas_object_show(wd->panes);
236
237    elm_panes_content_left_size_set(obj, 0.5);
238
239    edje_object_signal_callback_add(wd->panes, "elm,action,click", "",
240                                    _clicked, obj);
241    edje_object_signal_callback_add(wd->panes, "elm,action,click,double", "",
242                                    _clicked_double, obj);
243    edje_object_signal_callback_add(wd->panes, "elm,action,press", "",
244                                    _press, obj);
245    edje_object_signal_callback_add(wd->panes, "elm,action,unpress", "",
246                                    _unpress, obj);
247
248    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
249    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
250                                   _changed_size_hints, obj);
251
252    _mirrored_set(obj, elm_widget_mirrored_get(obj));
253    _sizing_eval(obj);
254    return obj;
255 }
256
257
258 /**
259  * Set the left/top content of the panes widget
260  *
261  * Once the content object is set, a previously set one will be deleted.
262  * If you want to keep that old content object, use the
263  * elm_panes_content_left_unset() function.
264  *
265  * @param[in] obj The panes object
266  * @param[in] content The new left/top content object
267  *
268  * @ingroup Panes
269  */
270 EAPI void
271 elm_panes_content_left_set(Evas_Object *obj, Evas_Object *content)
272 {
273    ELM_CHECK_WIDTYPE(obj, widtype);
274    Widget_Data *wd = elm_widget_data_get(obj);
275    if (wd->contents.left)
276      {
277         evas_object_del(wd->contents.left);
278         wd->contents.left = NULL;
279      }
280    if (content)
281      {
282         wd->contents.left = content;
283         elm_widget_sub_object_add(obj, content);
284         edje_object_part_swallow(wd->panes, "elm.swallow.left", content);
285         if (wd->contents.right)
286           edje_object_signal_emit(wd->panes, "elm.panes.pair", "elm");
287      }
288    else
289       edje_object_signal_emit(wd->panes, "elm.panes.unpair", "elm");
290 }
291
292 /**
293  * Set the right/bottom content of the panes widget
294  *
295  * Once the content object is set, a previously set one will be deleted.
296  * If you want to keep that old content object, use the
297  * elm_panes_content_right_unset() function.
298  *
299  * @param[in] obj The panes object
300  * @param[in] content The new right/bottom content object
301  *
302  * @ingroup Panes
303  */
304 EAPI void
305 elm_panes_content_right_set(Evas_Object *obj, Evas_Object *content)
306 {
307    ELM_CHECK_WIDTYPE(obj, widtype);
308    Widget_Data *wd = elm_widget_data_get(obj);
309    if (wd->contents.right)
310      {
311         evas_object_del(wd->contents.right);
312         wd->contents.right = NULL;
313      }
314    if (content)
315      {
316         wd->contents.right = content;
317         elm_widget_sub_object_add(obj, content);
318         edje_object_part_swallow(wd->panes, "elm.swallow.right", content);
319         if (wd->contents.left)
320           edje_object_signal_emit(wd->panes, "elm.panes.pair", "elm");
321      }
322    else
323      edje_object_signal_emit(wd->panes, "elm.panes.unpair", "elm");
324 }
325
326 /**
327  * Get the left/top content used for the panes
328  *
329  * Return the left/top content object which is set for this widget.
330  *
331  * @param[in] obj The panes object
332  * @return The left/top content object that is being used
333  *
334  * @ingroup Panes
335  */
336 EAPI Evas_Object *
337 elm_panes_content_left_get(const Evas_Object *obj)
338 {
339    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
340    Widget_Data *wd = elm_widget_data_get(obj);
341    return wd->contents.left;
342 }
343
344 /**
345  * Get the right/bottom content used for the panes
346  *
347  * Return the right/bottom content object which is set for this widget.
348  *
349  * @param[in] obj The panes object
350  * @return The right/bottom content object that is being used
351  *
352  * @ingroup Panes
353  */
354 EAPI Evas_Object *
355 elm_panes_content_right_get(const Evas_Object *obj)
356 {
357    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
358    Widget_Data *wd = elm_widget_data_get(obj);
359    return wd->contents.right;
360 }
361
362 /**
363  * Unset the left/top content used for the panes
364  *
365  * Unparent and return the left content object which was set for this widget.
366  *
367  * @param[in] obj The panes object
368  * @return The left/top content object that was being used
369  *
370  * @ingroup Panes
371  */
372 EAPI Evas_Object *
373 elm_panes_content_left_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.left) return NULL;
379    Evas_Object *content = wd->contents.left;
380    elm_widget_sub_object_del(obj, content);
381    edje_object_part_unswallow(wd->panes, content);
382    evas_object_hide(content);
383    wd->contents.left = NULL;
384    edje_object_signal_emit(wd->panes, "elm.panes.unpair", "elm");
385    return content;
386 }
387
388 /**
389  * Unset the right/bottom content used for the panes
390  *
391  * Unparent and return the right content object which was set for this widget.
392  *
393  * @param[in] obj The panes object
394   * @return The right/bottom content object that was being used
395  *
396  * @ingroup Panes
397  */
398 EAPI Evas_Object *
399 elm_panes_content_right_unset(Evas_Object *obj)
400 {
401    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
402    Widget_Data *wd = elm_widget_data_get(obj);
403    if (!wd) return NULL;
404    if (!wd->contents.right) return NULL;
405    Evas_Object *content = wd->contents.right;
406    elm_widget_sub_object_del(obj, content);
407    edje_object_part_unswallow(wd->panes, content);
408    evas_object_hide(content);
409    wd->contents.right = NULL;
410    edje_object_signal_emit(wd->panes, "elm.panes.unpair", "elm");
411    return content;
412 }
413
414 /**
415  * Get the relative normalized size of left/top content of the pane
416  *
417  * @param[in] obj The panes object
418  * @return The value of type double in the range [0.0,1.0]
419  *
420  * @ingroup Panes
421  */
422 EAPI double 
423 elm_panes_content_left_size_get(const Evas_Object *obj)
424 {
425    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
426    Widget_Data *wd = elm_widget_data_get(obj);
427    double w, h;
428
429    edje_object_part_drag_value_get(wd->panes, "elm.bar", &w, &h);
430    if (wd->horizontal) return h;
431    else return w;
432 }
433
434 /**
435  * Set a size of the left/top content with a relative normalized double value
436  *
437  * @param[in] obj The panes object
438  * @param[in] size The value of type double in the range [0.0,1.0]
439  *
440  * @ingroup Panes
441  */
442 EAPI void 
443 elm_panes_content_left_size_set(Evas_Object *obj, double size)
444 {
445    ELM_CHECK_WIDTYPE(obj, widtype);
446    Widget_Data *wd = elm_widget_data_get(obj);
447
448    if (size < 0.0) size = 0.0;
449    else if (size > 1.0) size = 1.0;
450    if (wd->horizontal)
451      edje_object_part_drag_value_set(wd->panes, "elm.bar", 0.0, size);
452    else
453      edje_object_part_drag_value_set(wd->panes, "elm.bar", size, 0.0);
454 }
455
456 /**
457  * Set the type of an existing panes object to horizontal/vertical
458  *
459  * By default the panes is of vertical type
460  *
461  * @param[in] obj The panes object
462  * @param[in] horizontal Boolean value. If true, then the type is set to horizontal else vertical
463  *
464  * @ingroup Panes
465  */
466 EAPI void 
467 elm_panes_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
468 {
469    ELM_CHECK_WIDTYPE(obj, widtype);
470    Widget_Data *wd = elm_widget_data_get(obj);
471
472    wd->horizontal = horizontal;
473    _theme_hook(obj);
474    elm_panes_content_left_size_set(obj, 0.5);
475 }
476
477 /**
478  * Indicate if the type of pane object is horizontal or not
479  *
480  * @param[in] obj The panes object
481  * @return true if it is of horizontal type else false
482  *
483  * @ingroup Panes
484  */
485 EAPI Eina_Bool 
486 elm_panes_horizontal_get(const Evas_Object *obj)
487 {
488    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
489    Widget_Data *wd = elm_widget_data_get(obj);
490    return wd->horizontal;
491 }
492
493 /**
494  * Set a handler of the pane object movable or non-movable
495  *
496  * @param[in] obj The panes object
497  * @param[in] fixed If set to true then the views size can't be changed using handler otherwise using handler they can be resized
498  *
499  * @ingroup Panes
500  */
501 EAPI void
502 elm_panes_fixed_set(Evas_Object *obj, Eina_Bool fixed)
503 {
504    ELM_CHECK_WIDTYPE(obj, widtype);
505    Widget_Data *wd = elm_widget_data_get(obj);
506    wd->fixed = fixed;
507    if (wd->fixed == EINA_TRUE)
508      edje_object_signal_emit(wd->panes, "elm.panes.fixed", "elm");
509    else
510      edje_object_signal_emit(wd->panes, "elm.panes.unfixed", "elm");
511 }
512
513 /**
514  * Indicate if the handler of the panes object can be moved with user interaction
515  *
516  * @param[in] obj The panes object
517  * @return false if the views can be resized using handler else true
518  *
519  * @ingroup Panes
520  */
521 EAPI Eina_Bool
522 elm_panes_fixed_get(const Evas_Object *obj)
523 {
524    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
525    Widget_Data *wd = elm_widget_data_get(obj);
526    return wd->fixed;
527 }