a435f641d99922c90090b6d93063bf12a40fb4de
[framework/uifw/elementary.git] / src / lib / elm_panel.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Panel Panel
6  * @ingroup Elementary
7  *
8  * A panel is a type of animated container that contains subobjects.  It
9  * can be expanded or contracted.
10  *
11  * Orientations are as follows:
12  * ELM_PANEL_ORIENT_TOP
13  * ELM_PANEL_ORIENT_BOTTOM
14  * ELM_PANEL_ORIENT_LEFT
15  * ELM_PANEL_ORIENT_RIGHT
16  * NOTE: Only LEFT and RIGHT orientations are implemented.
17  *
18  * THIS WIDGET IS UNDER CONSTRUCTION!
19  */
20
21 typedef struct _Widget_Data Widget_Data;
22 struct _Widget_Data 
23 {
24    Evas_Object *scr, *bx, *content;
25    Elm_Panel_Orient orient;
26    Eina_Bool hidden : 1;
27 };
28
29 static const char *widtype = NULL;
30 static void _del_hook(Evas_Object *obj);
31 static void _theme_hook(Evas_Object *obj);
32 static void _sizing_eval(Evas_Object *obj);
33 static void _resize(void *data, Evas *evas, Evas_Object *obj, void *event);
34 static void _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data);
35 static void _toggle_panel(void *data, Evas_Object *obj, const char *emission, const char *source);
36
37 static void 
38 _del_hook(Evas_Object *obj) 
39 {
40    Widget_Data *wd = elm_widget_data_get(obj);
41    if (!wd) return;
42    free(wd);
43 }
44
45 static void 
46 _theme_hook(Evas_Object *obj) 
47 {
48    Widget_Data *wd = elm_widget_data_get(obj);
49    if (!wd) return;
50    elm_smart_scroller_object_theme_set(obj, wd->scr, "panel", "base", elm_widget_style_get(obj));
51 //   scale = (elm_widget_scale_get(obj) * _elm_config->scale);
52 //   edje_object_scale_set(wd->scr, scale);
53    _sizing_eval(obj);
54 }
55
56 static void 
57 _sizing_eval(Evas_Object *obj) 
58 {
59    Widget_Data *wd = elm_widget_data_get(obj);
60    Evas_Coord mw = -1, mh = -1;
61    Evas_Coord vw = 0, vh = 0;
62    Evas_Coord w, h;
63    if (!wd) return;
64    evas_object_smart_calculate(wd->bx);
65    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), 
66                              &mw, &mh);
67    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
68    if (w < mw) w = mw;
69    if (h < mh) h = mh;
70    evas_object_resize(wd->scr, w, h);
71
72    evas_object_size_hint_min_get(wd->bx, &mw, &mh);
73    if (w > mw) mw = w;
74    if (h > mh) mh = h;
75    evas_object_resize(wd->bx, mw, mh);
76
77    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
78    mw = mw + (w - vw);
79    mh = mh + (h - vh);
80    evas_object_size_hint_min_set(obj, mw, mh);
81    evas_object_size_hint_max_set(obj, -1, -1);
82 }
83
84 static void 
85 _resize(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
86 {
87    Widget_Data *wd = elm_widget_data_get(data);
88    Evas_Coord mw, mh, vw, vh, w, h;
89    if (!wd) return;
90    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
91    evas_object_size_hint_min_get(wd->bx, &mw, &mh);
92    evas_object_geometry_get(wd->bx, NULL, NULL, &w, &h);
93    if ((vw >= mw) || (vh >= mh))
94      {
95         if ((w != vw) || (h != vh)) evas_object_resize(wd->bx, vw, vh);
96      }
97 }
98
99 static void 
100 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data) 
101 {
102    Widget_Data *wd = data;
103    if (!wd) return;
104    _els_box_layout(o, priv, EINA_TRUE, EINA_FALSE);
105 }
106
107 static void 
108 _toggle_panel(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) 
109 {
110    Widget_Data *wd = elm_widget_data_get(data);
111    if (!wd) return;
112    if (wd->hidden) 
113      {
114         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), 
115                                 "elm,action,show", "elm");
116         wd->hidden = EINA_FALSE;
117      }
118    else
119      {
120         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), 
121                                 "elm,action,hide", "elm");
122         wd->hidden = EINA_TRUE;
123      }
124 }
125
126 /**
127  * Adds a panel object
128  *
129  * @param parent The parent object
130  *
131  * @return The panel object, or NULL on failure
132  *
133  * @ingroup Panel
134  */
135 EAPI Evas_Object *
136 elm_panel_add(Evas_Object *parent) 
137 {
138    Evas_Object *obj;
139    Evas *evas;
140    Widget_Data *wd;
141
142    wd = ELM_NEW(Widget_Data);
143    evas = evas_object_evas_get(parent);
144    obj = elm_widget_add(evas);
145    ELM_SET_WIDTYPE(widtype, "panel");
146    elm_widget_type_set(obj, "panel");
147    elm_widget_sub_object_add(parent, obj);
148    elm_widget_data_set(obj, wd);
149    elm_widget_del_hook_set(obj, _del_hook);
150    elm_widget_theme_hook_set(obj, _theme_hook);
151    elm_widget_can_focus_set(obj, 0);
152
153    wd->scr = elm_smart_scroller_add(evas);
154    elm_smart_scroller_widget_set(wd->scr, obj);
155    elm_smart_scroller_object_theme_set(obj, wd->scr, "panel", "base", "left");
156    elm_smart_scroller_bounce_allow_set(wd->scr, 0, 0);
157    elm_widget_resize_object_set(obj, wd->scr);
158    elm_smart_scroller_policy_set(wd->scr, ELM_SMART_SCROLLER_POLICY_OFF, 
159                                  ELM_SMART_SCROLLER_POLICY_OFF);
160
161    wd->hidden = EINA_FALSE;
162    wd->orient = ELM_PANEL_ORIENT_LEFT;
163
164    wd->bx = evas_object_box_add(evas);
165    evas_object_size_hint_align_set(wd->bx, 0.5, 0.5);
166    evas_object_box_layout_set(wd->bx, _layout, wd, NULL);
167    elm_widget_sub_object_add(obj, wd->bx);
168    elm_smart_scroller_child_set(wd->scr, wd->bx);
169    evas_object_show(wd->bx);
170
171    edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr), 
172                                    "elm,action,panel,toggle", "*", 
173                                    _toggle_panel, obj);
174
175    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE, _resize, obj);
176
177    _sizing_eval(obj);
178    return obj;
179 }
180
181 /**
182  * Sets the orientation of the panel
183  *
184  * @param parent The parent object
185  * @param orient The panel orientation.  Can be one of the following:
186  * ELM_PANEL_ORIENT_TOP
187  * ELM_PANEL_ORIENT_BOTTOM
188  * ELM_PANEL_ORIENT_LEFT
189  * ELM_PANEL_ORIENT_RIGHT
190  *
191  * NOTE: Only LEFT and RIGHT orientations are implemented.
192  *
193  * @ingroup Panel
194  */
195 EAPI void 
196 elm_panel_orient_set(Evas_Object *obj, Elm_Panel_Orient orient) 
197 {
198    ELM_CHECK_WIDTYPE(obj, widtype);
199    Widget_Data *wd = elm_widget_data_get(obj);
200    if (!wd) return;
201    wd->orient = orient;
202    switch (orient) 
203      {
204      case ELM_PANEL_ORIENT_TOP:
205      case ELM_PANEL_ORIENT_BOTTOM:
206         break;
207      case ELM_PANEL_ORIENT_LEFT:
208         elm_smart_scroller_object_theme_set(obj, wd->scr, "panel", "base", "left");
209         break;
210      case ELM_PANEL_ORIENT_RIGHT:
211         elm_smart_scroller_object_theme_set(obj, wd->scr, "panel", "base", "right");
212         break;
213      default:
214         break;
215      }
216    _sizing_eval(obj);
217 }
218
219 /**
220  * Get the orientation of the panel.
221  *
222  * @param obj The panel object
223  * @return The Elm_Panel_Orient, or ELM_PANEL_ORIENT_LEFT on failure.
224  *
225  * @ingroup Panel
226  */
227 EAPI Elm_Panel_Orient
228 elm_panel_orient_get(Evas_Object *obj)
229 {
230    ELM_CHECK_WIDTYPE(obj, widtype) ELM_PANEL_ORIENT_LEFT;
231    Widget_Data *wd = elm_widget_data_get(obj);
232    if (!wd) return ELM_PANEL_ORIENT_LEFT;
233    return wd->orient;   
234 }
235
236 /**
237  * Set the content of the panel.
238  *
239  * Once the content object is set, a previously set one will be deleted.
240  * If you want to keep that old content object, use the
241  * elm_panel_content_unset() function.
242  *
243  * @param obj The panel object
244  * @param content The panel content
245  *
246  * @ingroup Panel
247  */
248 EAPI void
249 elm_panel_content_set(Evas_Object *obj, Evas_Object *content)
250 {
251    ELM_CHECK_WIDTYPE(obj, widtype);
252    Widget_Data *wd = elm_widget_data_get(obj);
253    if (!wd) return;
254    if (wd->content == content) return;
255    if (wd->content)
256      evas_object_box_remove_all(wd->bx, EINA_TRUE);
257    wd->content = content;
258    if (content)
259      {
260         evas_object_box_append(wd->bx, wd->content);
261         evas_object_show(wd->content);
262      }
263    _sizing_eval(obj);
264 }
265
266 /**
267  * Unset the content of the panel.
268  *
269  * Unparent and return the content object which was set for this widget.
270  *
271  * @param obj The panel object
272  * @return The content that was being used
273  *
274  * @ingroup Panel
275  */
276 EAPI Evas_Object *
277 elm_panel_content_unset(Evas_Object *obj)
278 {
279    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
280    Widget_Data *wd = elm_widget_data_get(obj);
281    Evas_Object *content;
282    if (!wd) return NULL;
283    if (!wd->content) return NULL;
284    content = wd->content;
285    evas_object_box_remove_all(wd->bx, EINA_FALSE);
286    wd->content = NULL;
287    return content;
288 }
289
290 /**
291  * Set the state of the panel.
292  *
293  * @param obj The panel object
294  * @param hidden If true, the panel will run the edje animation to contract
295  *
296  * @ingroup Panel
297  */
298 EAPI void
299 elm_panel_hidden_set(Evas_Object *obj, Eina_Bool hidden)
300 {
301    ELM_CHECK_WIDTYPE(obj, widtype);
302    Widget_Data *wd = elm_widget_data_get(obj);
303    if (!wd) return;
304    if (wd->hidden == hidden) return;
305    wd->hidden = hidden;
306    _toggle_panel(obj, NULL, "elm,action,panel,toggle", "*");
307 }
308
309 /**
310  * Get the state of the panel.
311  *
312  * @param obj The panel object
313  * @param hidden If true, the panel is in the "hide" state
314  *
315  * @ingroup Panel
316  */
317 EAPI Eina_Bool
318 elm_panel_hidden_get(Evas_Object *obj)
319 {
320    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
321    Widget_Data *wd = elm_widget_data_get(obj);
322    if (!wd) return EINA_FALSE;
323    return wd->hidden;
324 }
325
326 /**
327  * Toggle the state of the panel from code
328  *
329  * @param obj The panel object
330  *
331  * @ingroup Panel
332  */
333 EAPI void
334 elm_panel_toggle(Evas_Object *obj)
335 {
336    ELM_CHECK_WIDTYPE(obj, widtype);
337    Widget_Data *wd = elm_widget_data_get(obj);
338    if (!wd) return;
339    wd->hidden = !(wd->hidden);
340    _toggle_panel(obj, NULL, "elm,action,panel,toggle", "*");
341 }