elm: change elm_object_content_part_set/get/unset to elm_object_part_content_set...
[framework/uifw/elementary.git] / src / lib / elc_hoversel.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5
6 struct _Widget_Data
7 {
8    Evas_Object *btn, *hover;
9    Evas_Object *hover_parent;
10    Eina_List *items;
11    Eina_Bool horizontal : 1;
12    Eina_Bool expanded   : 1;
13 };
14
15 struct _Elm_Hoversel_Item
16 {
17    ELM_WIDGET_ITEM;
18    const char *label;
19    const char *icon_file;
20    const char *icon_group;
21    Elm_Icon_Type icon_type;
22    Evas_Smart_Cb func;
23 };
24
25 static const char *widtype = NULL;
26 static void _del_pre_hook(Evas_Object *obj);
27 static void _del_hook(Evas_Object *obj);
28 static void _activate(Evas_Object *obj);
29 static void _activate_hook(Evas_Object *obj);
30 static void _disable_hook(Evas_Object *obj);
31 static void _sizing_eval(Evas_Object *obj);
32 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
33 static void _parent_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
34
35 static const char SIG_CLICKED[] = "clicked";
36 static const char SIG_SELECTED[] = "selected";
37 static const char SIG_DISMISSED[] = "dismissed";
38
39 static const Evas_Smart_Cb_Description _signals[] = {
40    {SIG_CLICKED, ""},
41    {SIG_SELECTED, ""},
42    {SIG_DISMISSED, ""},
43    {NULL, NULL}
44 };
45
46 static void
47 _del_pre_hook(Evas_Object *obj)
48 {
49    Elm_Hoversel_Item *item;
50    Widget_Data *wd = elm_widget_data_get(obj);
51    if (!wd) return;
52    evas_object_event_callback_del_full(wd->btn, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
53                                        _changed_size_hints, obj);
54    elm_hoversel_hover_end(obj);
55    elm_hoversel_hover_parent_set(obj, NULL);
56    EINA_LIST_FREE(wd->items, item)
57      {
58         elm_widget_item_pre_notify_del(item);
59         eina_stringshare_del(item->label);
60         eina_stringshare_del(item->icon_file);
61         eina_stringshare_del(item->icon_group);
62         elm_widget_item_del(item);
63      }
64 }
65
66 static void
67 _del_hook(Evas_Object *obj)
68 {
69    Widget_Data *wd = elm_widget_data_get(obj);
70    if (!wd) return;
71    free(wd);
72 }
73
74 static void
75 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
76 {
77    Widget_Data *wd = elm_widget_data_get(obj);
78    if (!wd) return;
79    elm_widget_mirrored_set(wd->btn, rtl);
80    elm_widget_mirrored_set(wd->hover, rtl);
81 }
82
83 static void
84 _theme_hook(Evas_Object *obj)
85 {
86    Widget_Data *wd = elm_widget_data_get(obj);
87    char buf[4096];
88    if (!wd) return;
89    _elm_widget_mirrored_reload(obj);
90
91    elm_hoversel_hover_end(obj);
92    if (wd->horizontal)
93      snprintf(buf, sizeof(buf), "hoversel_horizontal/%s", elm_widget_style_get(obj));
94    else
95      snprintf(buf, sizeof(buf), "hoversel_vertical/%s", elm_widget_style_get(obj));
96    elm_object_style_set(wd->btn, buf);
97    elm_object_disabled_set(wd->btn, elm_widget_disabled_get(obj));
98    _mirrored_set(obj, elm_widget_mirrored_get(obj));
99 }
100
101 static void
102 _disable_hook(Evas_Object *obj)
103 {
104    Widget_Data *wd = elm_widget_data_get(obj);
105    if (!wd) return;
106    elm_object_disabled_set(wd->btn, elm_widget_disabled_get(obj));
107 }
108
109 static void
110 _sizing_eval(Evas_Object *obj)
111 {
112    Widget_Data *wd = elm_widget_data_get(obj);
113    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
114    if (!wd) return;
115    evas_object_size_hint_min_get(wd->btn, &minw, &minh);
116    evas_object_size_hint_max_get(wd->btn, &maxw, &maxh);
117    evas_object_size_hint_min_set(obj, minw, minh);
118    evas_object_size_hint_max_set(obj, maxw, maxh);
119 }
120
121 static void
122 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
123 {
124    Widget_Data *wd = elm_widget_data_get(obj);
125    if (!wd) return;
126    if (elm_widget_focus_get(obj))
127      elm_widget_focus_steal(wd->btn);
128 }
129
130 static void
131 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
132 {
133    _sizing_eval(data);
134 }
135
136 static void
137 _hover_clicked(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
138 {
139    elm_hoversel_hover_end(data);
140 }
141
142 static void
143 _item_clicked(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
144 {
145    Elm_Hoversel_Item *item = data;
146    Evas_Object *obj2 = WIDGET(item);
147
148    elm_hoversel_hover_end(obj2);
149    if (item->func) item->func((void *)item->base.data, obj2, item);
150    evas_object_smart_callback_call(obj2, SIG_SELECTED, item);
151 }
152
153 static void
154 _activate(Evas_Object *obj)
155 {
156    Widget_Data *wd = elm_widget_data_get(obj);
157    Evas_Object *bt, *bx, *ic;
158    const Eina_List *l;
159    const Elm_Hoversel_Item *item;
160    char buf[4096];
161
162    if (!wd) return;
163    if (wd->expanded)
164      {
165         elm_hoversel_hover_end(obj);
166         return;
167      }
168    wd->expanded = EINA_TRUE;
169
170    if (elm_widget_disabled_get(obj)) return;
171    wd->hover = elm_hover_add(obj);
172    elm_widget_mirrored_automatic_set(wd->hover, EINA_FALSE);
173    if (wd->horizontal)
174      snprintf(buf, sizeof(buf), "hoversel_horizontal/%s", elm_widget_style_get(obj));
175    else
176      snprintf(buf, sizeof(buf), "hoversel_vertical/%s", elm_widget_style_get(obj));
177    elm_object_style_set(wd->hover, buf);
178    evas_object_smart_callback_add(wd->hover, "clicked", _hover_clicked, obj);
179    elm_hover_parent_set(wd->hover, wd->hover_parent);
180    elm_hover_target_set(wd->hover, wd->btn);
181
182    bx = elm_box_add(wd->hover);
183    elm_widget_mirrored_automatic_set(bx, EINA_FALSE);
184    elm_box_homogeneous_set(bx, 1);
185
186    elm_box_horizontal_set(bx, wd->horizontal);
187
188    if (wd->horizontal)
189      snprintf(buf, sizeof(buf), "hoversel_horizontal_entry/%s",
190               elm_widget_style_get(obj));
191    else
192      snprintf(buf, sizeof(buf), "hoversel_vertical_entry/%s",
193               elm_widget_style_get(obj));
194    EINA_LIST_FOREACH(wd->items, l, item)
195      {
196         bt = elm_button_add(wd->hover);
197         elm_widget_mirrored_automatic_set(bt, EINA_FALSE);
198         elm_widget_mirrored_set(bt, elm_widget_mirrored_get(obj));
199         elm_object_style_set(bt, buf);
200         elm_object_text_set(bt, item->label);
201         if (item->icon_file)
202           {
203              ic = elm_icon_add(obj);
204              elm_icon_scale_set(ic, 0, 1);
205              if (item->icon_type == ELM_ICON_FILE)
206                elm_icon_file_set(ic, item->icon_file, item->icon_group);
207              else if (item->icon_type == ELM_ICON_STANDARD)
208                elm_icon_standard_set(ic, item->icon_file);
209              elm_object_part_content_set(bt, "icon", ic);
210              evas_object_show(ic);
211           }
212         evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
213         evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
214         elm_box_pack_end(bx, bt);
215         evas_object_smart_callback_add(bt, "clicked", _item_clicked, item);
216         evas_object_show(bt);
217      }
218
219    if (wd->horizontal)
220      elm_hover_content_set(wd->hover,
221                            elm_hover_best_content_location_get(wd->hover,
222                                                                ELM_HOVER_AXIS_HORIZONTAL),
223                            bx);
224    else
225      elm_hover_content_set(wd->hover,
226                            elm_hover_best_content_location_get(wd->hover,
227                                                                ELM_HOVER_AXIS_VERTICAL),
228                            bx);
229    evas_object_show(bx);
230
231    evas_object_show(wd->hover);
232    evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
233
234    //   if (wd->horizontal) evas_object_hide(wd->btn);
235 }
236
237 static void
238 _activate_hook(Evas_Object *obj)
239 {
240    _activate(obj);
241 }
242
243 static void
244 _button_clicked(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
245 {
246    _activate(data);
247 }
248
249 static void
250 _parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
251 {
252    Widget_Data *wd = elm_widget_data_get(data);
253    if (!wd) return;
254    wd->hover_parent = NULL;
255 }
256
257 static void
258 _elm_hoversel_label_set(Evas_Object *obj, const char *item, const char *label)
259 {
260    ELM_CHECK_WIDTYPE(obj, widtype);
261    Widget_Data *wd = elm_widget_data_get(obj);
262    if (item && strcmp(item, "default")) return;
263    if (!wd) return;
264    elm_object_text_set(wd->btn, label);
265 }
266
267 static const char *
268 _elm_hoversel_label_get(const Evas_Object *obj, const char *item)
269 {
270    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
271    Widget_Data *wd = elm_widget_data_get(obj);
272    if (item && strcmp(item, "default")) return NULL;
273    if ((!wd) || (!wd->btn)) return NULL;
274    return elm_object_text_get(wd->btn);
275 }
276
277 EAPI Evas_Object *
278 elm_hoversel_add(Evas_Object *parent)
279 {
280    Evas_Object *obj;
281    Evas *e;
282    Widget_Data *wd;
283
284    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
285
286    ELM_SET_WIDTYPE(widtype, "hoversel");
287    elm_widget_type_set(obj, "hoversel");
288    elm_widget_sub_object_add(parent, obj);
289    elm_widget_data_set(obj, wd);
290    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
291    elm_widget_del_hook_set(obj, _del_hook);
292    elm_widget_theme_hook_set(obj, _theme_hook);
293    elm_widget_disable_hook_set(obj, _disable_hook);
294    elm_widget_activate_hook_set(obj, _activate_hook);
295    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
296    elm_widget_can_focus_set(obj, EINA_TRUE);
297    elm_widget_text_set_hook_set(obj, _elm_hoversel_label_set);
298    elm_widget_text_get_hook_set(obj, _elm_hoversel_label_get);
299
300    wd->btn = elm_button_add(parent);
301    elm_widget_mirrored_automatic_set(wd->btn, EINA_FALSE);
302    wd->expanded = EINA_FALSE;
303    elm_widget_resize_object_set(obj, wd->btn);
304    evas_object_event_callback_add(wd->btn, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
305                                   _changed_size_hints, obj);
306    evas_object_smart_callback_add(wd->btn, "clicked", _button_clicked, obj);
307    evas_object_smart_callbacks_descriptions_set(obj, _signals);
308
309    elm_widget_sub_object_add(obj, wd->btn);
310
311    elm_hoversel_hover_parent_set(obj, parent);
312    _theme_hook(obj);
313
314    return obj;
315 }
316
317 EAPI void
318 elm_hoversel_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
319 {
320    ELM_CHECK_WIDTYPE(obj, widtype);
321    Widget_Data *wd = elm_widget_data_get(obj);
322    if (!wd) return;
323    if (wd->hover_parent)
324      evas_object_event_callback_del_full(wd->hover_parent, EVAS_CALLBACK_DEL,
325                                          _parent_del, obj);
326    wd->hover_parent = parent;
327    if (wd->hover_parent)
328      evas_object_event_callback_add(wd->hover_parent, EVAS_CALLBACK_DEL,
329                                     _parent_del, obj);
330 }
331
332 EAPI Evas_Object *
333 elm_hoversel_hover_parent_get(const Evas_Object *obj)
334 {
335    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
336    Widget_Data *wd = elm_widget_data_get(obj);
337    if (!wd) return NULL;
338    return wd->hover_parent;
339 }
340
341 EAPI void
342 elm_hoversel_label_set(Evas_Object *obj, const char *label)
343 {
344    _elm_hoversel_label_set(obj, NULL, label);
345 }
346
347 EAPI const char *
348 elm_hoversel_label_get(const Evas_Object *obj)
349 {
350    return _elm_hoversel_label_get(obj, NULL);
351 }
352
353 EAPI void
354 elm_hoversel_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
355 {
356    ELM_CHECK_WIDTYPE(obj, widtype);
357    Widget_Data *wd = elm_widget_data_get(obj);
358    if (!wd) return;
359    wd->horizontal = !!horizontal;
360 }
361
362 EAPI Eina_Bool
363 elm_hoversel_horizontal_get(const Evas_Object *obj)
364 {
365    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
366    Widget_Data *wd = elm_widget_data_get(obj);
367    if (!wd) return EINA_FALSE;
368    return wd->horizontal;
369 }
370
371 EAPI void
372 elm_hoversel_icon_set(Evas_Object *obj, Evas_Object *icon)
373 {
374    ELM_CHECK_WIDTYPE(obj, widtype);
375    Widget_Data *wd = elm_widget_data_get(obj);
376    if (!wd) return;
377    elm_object_part_content_set(wd->btn, "icon", icon);
378 }
379
380 EAPI Evas_Object *
381 elm_hoversel_icon_get(const Evas_Object *obj)
382 {
383    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
384    Widget_Data *wd = elm_widget_data_get(obj);
385    if ((!wd) || (!wd->btn)) return NULL;
386    return elm_object_part_content_get(wd->btn, "icon");
387 }
388
389 EAPI Evas_Object *
390 elm_hoversel_icon_unset(Evas_Object *obj)
391 {
392    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
393    Widget_Data *wd = elm_widget_data_get(obj);
394    if ((!wd) || (!wd->btn)) return NULL;
395    return elm_object_part_content_unset(wd->btn, "icon");
396 }
397
398 EAPI void
399 elm_hoversel_hover_begin(Evas_Object *obj)
400 {
401    ELM_CHECK_WIDTYPE(obj, widtype);
402    Widget_Data *wd = elm_widget_data_get(obj);
403    if (!wd) return;
404    if (wd->hover) return;
405    _activate(obj);
406 }
407
408 EAPI void
409 elm_hoversel_hover_end(Evas_Object *obj)
410 {
411    ELM_CHECK_WIDTYPE(obj, widtype);
412    Widget_Data *wd = elm_widget_data_get(obj);
413    if (!wd) return;
414    if (!wd->hover) return;
415    wd->expanded = EINA_FALSE;
416    evas_object_del(wd->hover);
417    wd->hover = NULL;
418    evas_object_smart_callback_call(obj, SIG_DISMISSED, NULL);
419 }
420
421 EAPI Eina_Bool
422 elm_hoversel_expanded_get(const Evas_Object *obj)
423 {
424    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
425    Widget_Data *wd = elm_widget_data_get(obj);
426    if (!wd) return EINA_FALSE;
427    return (wd->hover) ? EINA_TRUE : EINA_FALSE;
428 }
429
430 EAPI void
431 elm_hoversel_clear(Evas_Object *obj)
432 {
433    Elm_Hoversel_Item *item;
434    Eina_List *l, *ll;
435    ELM_CHECK_WIDTYPE(obj, widtype);
436    Widget_Data *wd = elm_widget_data_get(obj);
437    if (!wd) return;
438    EINA_LIST_FOREACH_SAFE(wd->items, l, ll, item) elm_hoversel_item_del(item);
439 }
440
441 EAPI const Eina_List *
442 elm_hoversel_items_get(const Evas_Object *obj)
443 {
444    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
445    Widget_Data *wd = elm_widget_data_get(obj);
446    if (!wd) return NULL;
447    return wd->items;
448 }
449
450 EAPI Elm_Hoversel_Item *
451 elm_hoversel_item_add(Evas_Object *obj, const char *label, const char *icon_file, Elm_Icon_Type icon_type, Evas_Smart_Cb func, const void *data)
452 {
453    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
454    Widget_Data *wd = elm_widget_data_get(obj);
455    if (!wd) return NULL;
456    Elm_Hoversel_Item *item = elm_widget_item_new(obj, Elm_Hoversel_Item);
457    if (!item) return NULL;
458    wd->items = eina_list_append(wd->items, item);
459    item->label = eina_stringshare_add(label);
460    item->icon_file = eina_stringshare_add(icon_file);
461    item->icon_type = icon_type;
462    item->func = func;
463    item->base.data = data;
464    return item;
465 }
466
467 EAPI void
468 elm_hoversel_item_del(Elm_Hoversel_Item *item)
469 {
470    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
471    Widget_Data *wd = elm_widget_data_get(WIDGET(item));
472    if (!wd) return;
473    elm_hoversel_hover_end(WIDGET(item));
474    wd->items = eina_list_remove(wd->items, item);
475    elm_widget_item_pre_notify_del(item);
476    eina_stringshare_del(item->label);
477    eina_stringshare_del(item->icon_file);
478    eina_stringshare_del(item->icon_group);
479    elm_widget_item_del(item);
480 }
481
482 EAPI void
483 elm_hoversel_item_del_cb_set(Elm_Hoversel_Item *item, Evas_Smart_Cb func)
484 {
485    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
486    elm_widget_item_del_cb_set(item, func);
487 }
488
489 EAPI void *
490 elm_hoversel_item_data_get(const Elm_Hoversel_Item *item)
491 {
492    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
493    return elm_widget_item_data_get(item);
494 }
495
496 EAPI const char *
497 elm_hoversel_item_label_get(const Elm_Hoversel_Item *item)
498 {
499    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
500    return item->label;
501 }
502
503 EAPI void
504 elm_hoversel_item_icon_set(Elm_Hoversel_Item *item, const char *icon_file, const char *icon_group, Elm_Icon_Type icon_type)
505 {
506    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
507    eina_stringshare_replace(&item->icon_file, icon_file);
508    eina_stringshare_replace(&item->icon_group, icon_group);
509    item->icon_type = icon_type;
510 }
511
512 EAPI void
513 elm_hoversel_item_icon_get(const Elm_Hoversel_Item *item, const char **icon_file, const char **icon_group, Elm_Icon_Type *icon_type)
514 {
515    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
516    if (icon_file) *icon_file = item->icon_file;
517    if (icon_group) *icon_group = item->icon_group;
518    if (icon_type) *icon_type = item->icon_type;
519 }
520