Merge branch 'master' of 165.213.180.234:/git/slp/pkgs/elementary
[framework/uifw/elementary.git] / src / lib / elm_bubble.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Bubble Bubble
6  * @ingroup Elementary
7  *
8  * The Bubble is an widget used to show a text in a frame as speech is
9  * represented in comics.
10  */
11
12 typedef struct _Widget_Data Widget_Data;
13
14 struct _Widget_Data
15 {
16    Evas_Object *bbl;
17    Evas_Object *content, *icon, *sweep;
18    const char *label, *info;
19    
20    Eina_Bool down:1;
21    Evas_Coord_Point down_point;
22 };
23
24 #define SWEEP_THRESHOLD 100
25
26 static const char *widtype = NULL;
27 static void _del_hook(Evas_Object *obj);
28 static void _theme_hook(Evas_Object *obj);
29 static void _sizing_eval(Evas_Object *obj);
30 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
31 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
32
33 static void
34 _del_hook(Evas_Object *obj)
35 {
36    Widget_Data *wd = elm_widget_data_get(obj);
37    if (!wd) return;
38    if (wd->label) eina_stringshare_del(wd->label);
39    if (wd->info) eina_stringshare_del(wd->info);
40    free(wd);
41 }
42
43 static void
44 _theme_hook(Evas_Object *obj)
45 {
46    Widget_Data *wd = elm_widget_data_get(obj);
47    if (!wd) return;
48    _elm_theme_object_set(obj, wd->bbl, "bubble", "base", elm_widget_style_get(obj));
49    edje_object_part_text_set(wd->bbl, "elm.text", wd->label);
50    edje_object_part_text_set(wd->bbl, "elm.info", wd->info);
51    if (wd->content) edje_object_part_swallow(wd->bbl, "elm.swallow.content", wd->content); 
52    if (wd->icon)
53      {
54          edje_object_part_swallow(wd->bbl, "elm.swallow.icon", wd->icon);
55          edje_object_signal_emit(wd->bbl, "elm,state,icon,visible", "elm");
56         edje_object_message_signal_process(wd->bbl); 
57      }
58    edje_object_scale_set(wd->bbl, elm_widget_scale_get(obj) * _elm_config->scale);
59    _sizing_eval(obj);
60 }
61
62 static void
63 _sizing_eval(Evas_Object *obj)
64 {
65    Widget_Data *wd = elm_widget_data_get(obj);
66    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
67    if (!wd) return;
68    edje_object_size_min_calc(wd->bbl, &minw, &minh);
69    evas_object_size_hint_min_set(obj, minw, minh);
70    evas_object_size_hint_max_set(obj, maxw, maxh);
71 }
72
73 static void
74 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
75 {
76    Widget_Data *wd = elm_widget_data_get(data);
77    if (!wd) return;
78    _sizing_eval(data);
79 }
80
81 static void
82 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
83 {
84    Widget_Data *wd = elm_widget_data_get(obj);
85    Evas_Object *sub = event_info;
86    if (!wd) return;
87    evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
88                                   _changed_size_hints, obj);
89    if (sub == wd->content) wd->content = NULL;
90    else if (sub == wd->icon)
91      {
92         edje_object_signal_emit(wd->bbl, "elm,state,icon,hidden", "elm");
93         wd->icon = NULL;
94         edje_object_message_signal_process(wd->bbl);
95      }
96    else if (sub == wd->sweep) wd->sweep = NULL;
97    _sizing_eval(obj);
98 }
99
100 static void
101 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
102 {
103         Widget_Data *wd = elm_widget_data_get(data);
104         Evas_Event_Mouse_Down *ev = event_info;
105
106         wd->down = EINA_TRUE;
107         wd->down_point.x = ev->canvas.x;
108         wd->down_point.y = ev->canvas.y;
109 }
110
111 static void
112 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
113 {
114         Widget_Data *wd = elm_widget_data_get(data);
115         Evas_Event_Mouse_Up *ev = event_info;
116
117         if (!wd->down) return;
118
119         if (ev->canvas.x - wd->down_point.x > SWEEP_THRESHOLD)
120                 evas_object_smart_callback_call(data, "sweep,left,right", NULL);
121         else if (wd->down_point.x - ev->canvas.x > SWEEP_THRESHOLD)
122                 evas_object_smart_callback_call(data, "sweep,right,left", NULL);
123
124         wd->down = EINA_FALSE;
125         wd->down_point.x = 0;
126         wd->down_point.y = 0;   
127 }
128
129 /**
130  * Add a new bubble to the parent
131  *
132  * @param parent The parent object
133  * @return The new object or NULL if it cannot be created
134  *
135  * This function adds a text bubble to the given parent evas object.
136  *
137  * @ingroup Bubble
138  */
139 EAPI Evas_Object *
140 elm_bubble_add(Evas_Object *parent)
141 {
142    Evas_Object *obj;
143    Evas *e;
144    Widget_Data *wd;
145
146    wd = ELM_NEW(Widget_Data);
147    e = evas_object_evas_get(parent);
148    obj = elm_widget_add(e);
149    ELM_SET_WIDTYPE(widtype, "bubble");
150    elm_widget_type_set(obj, "bubble");
151    elm_widget_sub_object_add(parent, obj);
152    elm_widget_data_set(obj, wd);
153    elm_widget_del_hook_set(obj, _del_hook);
154    elm_widget_theme_hook_set(obj, _theme_hook);
155
156    wd->bbl = edje_object_add(e);
157    _elm_theme_object_set(obj, wd->bbl, "bubble", "base", "default");
158    elm_widget_resize_object_set(obj, wd->bbl);
159
160    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
161    evas_object_event_callback_add(wd->bbl, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
162    evas_object_event_callback_add(wd->bbl, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
163
164    wd->down = EINA_FALSE;
165    wd->down_point.x = 0;
166    wd->down_point.y = 0;
167
168    _sizing_eval(obj);
169    return obj;
170 }
171
172 /**
173  * Set the label of the bubble
174  *
175  * @param obj The bubble object
176  * @param label The string to set in the label
177  *
178  * This function sets the title of the bubble that is shown on top of
179  * the bubble.
180  *
181  * @ingroup Bubble
182  */
183 EAPI void
184 elm_bubble_label_set(Evas_Object *obj, const char *label)
185 {
186    ELM_CHECK_WIDTYPE(obj, widtype);
187    Widget_Data *wd = elm_widget_data_get(obj);
188    if (!wd) return;
189    if (label) edje_object_signal_emit(wd->bbl, "elm,state,label,visible", "elm");
190    else edje_object_signal_emit(wd->bbl, "elm,state,label,hidden", "elm");
191    eina_stringshare_replace(&wd->label, label);
192    edje_object_part_text_set(wd->bbl, "elm.text", label);
193    _sizing_eval(obj);
194 }
195
196 /**
197  * Get the label of the bubble
198  *
199  * @param obj The bubble object
200  * @return The string of set in the label
201  *
202  * This function gets the title of the bubble that is shown on top of
203  * the bubble.
204  *
205  * @ingroup Bubble
206  */
207 EAPI const char*
208 elm_bubble_label_get(const Evas_Object *obj)
209 {
210    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
211    Widget_Data *wd = elm_widget_data_get(obj);
212    if (!wd) return NULL;
213    return wd->label;
214 }
215
216 /**
217  * Set the info of the bubble
218  *
219  * @param obj The bubble object
220  * @param info The given info about the bubble
221  *
222  * This function sets the text shown on the top right of bubble.
223  * In the Anchorblock example of the Elementary tests application it
224  * shows time.
225  *
226  * @ingroup Bubble
227  *
228  */
229 EAPI void
230 elm_bubble_info_set(Evas_Object *obj, const char *info)
231 {
232    ELM_CHECK_WIDTYPE(obj, widtype);
233    Widget_Data *wd = elm_widget_data_get(obj);
234    if (!wd) return;
235    eina_stringshare_replace(&wd->info, info);
236    edje_object_part_text_set(wd->bbl, "elm.info", info);
237    _sizing_eval(obj);
238 }
239
240 /**
241  * Get the info of the bubble
242  *
243  * @param obj The bubble object
244  *
245  * @return The "info" string of the bubble
246  *
247  * This function gets the text set to be displayed at the top right of
248  * the bubble.
249  *
250  * @ingroup Bubble
251  *
252  */
253 EAPI const char *
254 elm_bubble_info_get(const Evas_Object *obj)
255 {
256    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
257    Widget_Data *wd = elm_widget_data_get(obj);
258    if (!wd) return NULL;
259    return wd->info;
260 }
261
262 /**
263  * Set the content to be shown in the bubble
264  *
265  * Once the content object is set, a previously set one will be deleted.
266  * If you want to keep the old content object, use the
267  * elm_bubble_content_unset() function.
268  *
269  * @param obj The bubble object
270  * @param content The given content of the bubble
271  *
272  * This function sets the content shown on the middle of the bubble.
273  * In the Anchorblock example of the Elementary tests application it
274  * shows time.
275  *
276  * @ingroup Bubble
277  */
278 EAPI void
279 elm_bubble_content_set(Evas_Object *obj, Evas_Object *content)
280 {
281    ELM_CHECK_WIDTYPE(obj, widtype);
282    Widget_Data *wd = elm_widget_data_get(obj);
283    if (!wd) return;
284    if (wd->content == content) return;
285    if (wd->content) evas_object_del(wd->content);
286    wd->content = content;
287    if (content)
288      {
289         elm_widget_sub_object_add(obj, content);
290         evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
291                                        _changed_size_hints, obj);
292         edje_object_part_swallow(wd->bbl, "elm.swallow.content", content);
293      }
294    _sizing_eval(obj);
295 }
296
297 /**
298   * Get the content shown in the bubble 
299   * 
300   * Return the content object which is set for this widget. 
301   * 
302   * @param obj The bubble object 
303   * @return The content that is being used 
304   * 
305   * @ingroup Bubble 
306   */ 
307  EAPI Evas_Object * 
308  elm_bubble_content_get(const Evas_Object *obj) 
309  { 
310     ELM_CHECK_WIDTYPE(obj, widtype) NULL; 
311     Widget_Data *wd = elm_widget_data_get(obj); 
312     if (!wd) return NULL; 
313     return wd->content; 
314  } 
315   
316  /** 
317  * Unset the content shown in the bubble
318  *
319  * Unparent and return the content object which was set for this widget.
320  *
321  * @param obj The bubble object
322  * @return The content that was being used
323  *
324  * @ingroup Bubble
325  */
326 EAPI Evas_Object *
327 elm_bubble_content_unset(Evas_Object *obj)
328 {
329    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
330    Widget_Data *wd = elm_widget_data_get(obj);
331    Evas_Object *content;
332    if (!wd) return NULL;
333    if (!wd->content) return NULL;
334    content = wd->content;
335    elm_widget_sub_object_del(obj, content);
336    edje_object_part_unswallow(wd->bbl, content);
337    wd->content = NULL;
338    return content;
339 }
340
341 /**
342  * Set the icon of the bubble
343  *
344  * Once the icon object is set, a previously set one will be deleted.
345   * If you want to keep the old content object, use the 
346   * elm_icon_content_unset() function. 
347  *
348  * @param obj The bubble object
349  * @param icon The given icon for the bubble
350  *
351  * @ingroup Bubble
352  */
353 EAPI void
354 elm_bubble_icon_set(Evas_Object *obj, Evas_Object *icon)
355 {
356    ELM_CHECK_WIDTYPE(obj, widtype);
357    Widget_Data *wd = elm_widget_data_get(obj);
358    if (!wd) return;
359    if (wd->icon == icon) return;
360    if (wd->icon) evas_object_del(wd->icon);
361    wd->icon = icon;
362    if (icon)
363      {
364         elm_widget_sub_object_add(obj, icon);
365         edje_object_part_swallow(wd->bbl, "elm.swallow.icon", icon);
366         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
367                                        _changed_size_hints, obj);
368         edje_object_signal_emit(wd->bbl, "elm,state,icon,visible", "elm");
369         edje_object_message_signal_process(wd->bbl);
370      }
371    _sizing_eval(obj);
372 }
373
374 /**
375  * Get the icon of the bubble
376  *
377  * @param obj The bubble object
378  * @return The icon for the bubble
379  *
380  * This function gets the icon shown on the top left of bubble.
381  *
382  * @ingroup Bubble
383  */
384 EAPI Evas_Object *
385 elm_bubble_icon_get(const Evas_Object *obj)
386 {
387    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
388    Widget_Data *wd = elm_widget_data_get(obj);
389    if (!wd) return NULL;
390    return wd->icon;
391 }
392
393  /** 
394   * Unset the icon of the bubble 
395   * 
396   * Unparent and return the icon object which was set for this widget. 
397   * 
398   * @param obj The bubble object 
399   * @return The icon that was being used 
400   * 
401   * @ingroup Bubble 
402   */ 
403  EAPI Evas_Object * 
404  elm_bubble_icon_unset(Evas_Object *obj) 
405  { 
406     ELM_CHECK_WIDTYPE(obj, widtype) NULL; 
407     Widget_Data *wd = elm_widget_data_get(obj); 
408     Evas_Object *icon; 
409     if (!wd) return NULL; 
410     if (!wd->icon) return NULL; 
411     icon = wd->icon; 
412     elm_widget_sub_object_del(obj, icon); 
413     edje_object_part_unswallow(wd->bbl, icon); 
414     wd->icon = NULL; 
415     return icon; 
416  } 
417
418 /**
419  * Set the sweep layout
420  *
421  * @param obj The bubble object
422  * @param content The given content of the bubble
423  *
424  * This function sets the sweep layout when "sweep,left,right"signal is emitted. 
425  *
426  * @ingroup Bubble
427  */
428 EAPI void
429 elm_bubble_sweep_layout_set(Evas_Object *obj, Evas_Object *sweep)
430 {
431    ELM_CHECK_WIDTYPE(obj, widtype);
432    Widget_Data *wd = elm_widget_data_get(obj);
433    if (!wd) return;
434    if (wd->sweep == sweep) return;
435    if (wd->sweep) evas_object_del(wd->sweep);
436    wd->sweep = sweep;
437    if (sweep)
438      {
439         elm_widget_sub_object_add(obj, sweep);
440         edje_object_part_swallow(wd->bbl, "elm.swallow.sweep", sweep);
441      }
442 }
443
444 /**
445  * Unset and hide the sweep layout
446  *
447  * @param obj The bubble object
448  * @param content The given content of the bubble
449  *
450  * This function sets the sweep layout when "sweep,right,left"signal is emitted. 
451  *
452  * @ingroup Bubble
453  */
454 EAPI Evas_Object *
455 elm_bubble_sweep_layout_unset(Evas_Object *obj)
456 {
457    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
458    Widget_Data *wd = elm_widget_data_get(obj);
459    Evas_Object *sweep;
460    if (!wd) return NULL;
461    if (!wd->sweep) return NULL;
462    sweep = wd->sweep;
463    elm_widget_sub_object_del(obj, sweep);
464    edje_object_part_unswallow(wd->bbl, sweep);
465    evas_object_hide(sweep);
466    wd->sweep = NULL;
467    return sweep;
468 }
469
470 /**
471  * Set the corner of the bubble
472  *
473  * @param obj The bubble object.
474  * @param corner The given corner for the bubble.
475  *
476  * This function sets the corner of the bubble.
477  *
478  * @ingroup Bubble
479  */
480 EAPI void
481 elm_bubble_corner_set(Evas_Object *obj, const char *corner)
482 {
483    ELM_CHECK_WIDTYPE(obj, widtype);
484    Widget_Data *wd = elm_widget_data_get(obj);
485    if (!wd) return;
486    _elm_theme_object_set(obj, wd->bbl, "bubble", corner, elm_widget_style_get(obj));
487    if (wd->icon)
488      edje_object_part_swallow(wd->bbl, "elm.swallow.icon", wd->icon);
489    if (wd->content)
490      edje_object_part_swallow(wd->bbl, "elm.swallow.content", wd->content);
491    // FIXME: fix label etc.
492    _sizing_eval(obj);
493 }