Fix entry unrealization issue in genlist
[framework/uifw/elementary.git] / src / lib / elc_multibuttonentry.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_multibuttonentry.h"
4
5 //#define _VI_EFFECT 0
6 //#define _BOX_VI
7
8 #ifdef _VI_EFFECT
9 #define TRANSIT_DURATION 0.167
10 #define ANIMATE_FRAME 10
11 #endif
12
13 EAPI const char ELM_MULTIBUTTONENTRY_SMART_NAME[] = "elm_multibuttonentry";
14
15 //widget signals
16 static const char SIG_ITEM_SELECTED[] = "item,selected";
17 static const char SIG_ITEM_ADDED[] = "item,added";
18 static const char SIG_ITEM_DELETED[] = "item,deleted";
19 static const char SIG_ITEM_CLICKED[] = "item,clicked";
20 static const char SIG_CLICKED[] = "clicked";
21 static const char SIG_FOCUSED[] = "focused";
22 static const char SIG_UNFOCUSED[] = "unfocused";
23 static const char SIG_EXPANDED[] = "expanded";
24 static const char SIG_CONTRACTED[] = "contracted";
25 static const char SIG_EXPAND_STATE_CHANGED[] = "expand,state,changed";
26 static const char SIG_LONGPRESSED[] = "longpressed";
27
28 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
29    {SIG_ITEM_SELECTED, ""},
30    {SIG_ITEM_ADDED, ""},
31    {SIG_ITEM_DELETED, ""},
32    {SIG_ITEM_CLICKED, ""},
33    {SIG_CLICKED, ""},
34    {SIG_FOCUSED, ""},
35    {SIG_UNFOCUSED, ""},
36    {SIG_EXPANDED, ""},
37    {SIG_CONTRACTED, ""},
38    {SIG_EXPAND_STATE_CHANGED, ""},
39    {SIG_LONGPRESSED, ""},
40    {NULL, NULL}
41 };
42
43 EVAS_SMART_SUBCLASS_NEW
44   (ELM_MULTIBUTTONENTRY_SMART_NAME, _elm_multibuttonentry,
45   Elm_Multibuttonentry_Smart_Class, Elm_Layout_Smart_Class,
46   elm_layout_smart_class_get, _smart_callbacks);
47
48 static Eina_Bool
49 _elm_multibuttonentry_smart_focus_next(const Evas_Object *obj,
50                                Elm_Focus_Direction dir,
51                                Evas_Object **next)
52 {
53    Eina_List *items = NULL;
54    Eina_List *elist = NULL;
55    Elm_Multibuttonentry_Item *it;
56
57    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
58
59    if (!sd)
60      return EINA_FALSE;
61
62    if (!elm_widget_focus_next_get(sd->box, dir, next))
63      {
64         elm_widget_focused_object_clear(sd->box);
65         elm_widget_focus_next_get(sd->box, dir, next);
66      }
67
68    EINA_LIST_FOREACH(sd->items, elist, it)
69      items = eina_list_append(items, it->base.access_obj);
70
71    return elm_widget_focus_list_next_get
72             (obj, items, eina_list_data_get, dir, next);
73 }
74
75 static char *
76 _access_label_info_cb(void *data, Evas_Object *obj __UNUSED__)
77 {
78    Evas_Object *mbe = (Evas_Object *)data;
79    const char *txt = NULL;
80
81    ELM_MULTIBUTTONENTRY_DATA_GET(mbe, sd);
82
83    if (!mbe) return NULL;
84
85    if (!txt)
86      {
87         txt = elm_object_part_text_get(sd->label, "mbe.label");
88         return strdup(txt);
89      }
90    else return strdup(txt);
91
92    return NULL;
93 }
94
95 static char *
96 _access_shrink_info_cb(void *data, Evas_Object *obj __UNUSED__)
97 {
98    Evas_Object *mbe = (Evas_Object *)data;
99    const char *txt = NULL;
100    Eina_Strbuf *buf = NULL;
101    char *str = NULL;
102
103    ELM_MULTIBUTTONENTRY_DATA_GET(mbe, sd);
104
105    if (!mbe) return NULL;
106
107    if (!txt) txt = elm_object_text_get(sd->end);
108    if (txt)
109      {
110         buf = eina_strbuf_new();
111         eina_strbuf_append(buf, E_("And "));
112         eina_strbuf_append(buf, txt);
113         eina_strbuf_append(buf, E_(" more"));
114         str = eina_strbuf_string_steal(buf);
115         eina_strbuf_free(buf);
116         return str;
117      }
118    return NULL;
119 }
120
121 static Eina_Bool
122 _guide_packed(Evas_Object *obj)
123 {
124    Eina_List *children;
125
126    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
127
128    if (!sd->guide) return EINA_FALSE;
129
130    children = elm_box_children_get(sd->box);
131    if (sd->guide == eina_list_data_get(eina_list_last(children)))
132      {
133         eina_list_free(children);
134         return EINA_TRUE;
135      }
136    else
137      {
138         eina_list_free(children);
139         return EINA_FALSE;
140      }
141 }
142
143 static Eina_Bool
144 _label_packed(Evas_Object *obj)
145 {
146    Eina_List *children;
147
148    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
149
150    if (!sd->label) return EINA_FALSE;
151
152    children = elm_box_children_get(sd->box);
153    if (sd->label == eina_list_data_get(children))
154      {
155         eina_list_free(children);
156         return EINA_TRUE;
157      }
158    else
159      {
160         eina_list_free(children);
161         return EINA_FALSE;
162      }
163 }
164
165 static void
166 _guide_set(Evas_Object *obj,
167            const char *text)
168 {
169    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
170
171    if (!sd->guide && !strlen(text)) return;
172
173    if (!sd->guide)
174      {
175         sd->guide = elm_layout_add(obj);
176         elm_layout_theme_set
177            (sd->guide, "multibuttonentry", "guidetext", elm_widget_style_get(obj));
178         evas_object_size_hint_weight_set
179            (sd->guide, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
180         evas_object_size_hint_align_set
181            (sd->guide, EVAS_HINT_FILL, EVAS_HINT_FILL);
182      }
183    elm_object_text_set(sd->guide, text);
184
185    if (!sd->items && !elm_object_focus_get(obj) && !_guide_packed(obj))
186      {
187         if (sd->editable)
188           {
189              elm_box_unpack(sd->box, sd->entry);
190              evas_object_hide(sd->entry);
191           }
192
193         elm_box_pack_end(sd->box, sd->guide);
194         evas_object_show(sd->guide);
195      }
196 }
197
198 static void
199 _label_set(Evas_Object *obj,
200            const char *text)
201 {
202    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
203
204    if (!sd->label && !strlen(text)) return;
205
206    if (!sd->label)
207      {
208         sd->label = elm_layout_add(obj);
209         elm_layout_theme_set
210            (sd->label, "multibuttonentry", "label", elm_widget_style_get(obj));
211      }
212    elm_object_part_text_set(sd->label, "mbe.label", text);
213
214    if (strlen(text) && !_label_packed(obj))
215      {
216         elm_box_pack_start(sd->box, sd->label);
217         evas_object_show(sd->label);
218      }
219    else if (!strlen(text) && _label_packed(obj))
220      {
221         elm_box_unpack(sd->box, sd->label);
222         evas_object_hide(sd->label);
223      }
224
225    // ACCESS
226    if (_elm_config->access_mode)
227      {
228         _elm_access_object_register(obj, ELM_WIDGET_DATA(sd)->resize_obj);
229         _elm_access_callback_set(_elm_access_object_get(obj), ELM_ACCESS_INFO, _access_label_info_cb, obj);
230      }
231 }
232
233 #ifdef _VI_EFFECT
234 static void
235 _box_layout_pre_calculate(Evas_Object *obj,
236                           Elm_Multibuttonentry_Item *except_it,
237                           Evas_Coord *minh_wo_entry,
238                           Evas_Coord *minh)
239 {
240    Evas_Coord mnw, mnh, x, w, hpad = 0, vpad = 0;
241    Evas_Coord linew = 0, lineh = 0;
242    int line_num;
243    Eina_List *l;
244    Elm_Multibuttonentry_Item *it;
245
246    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
247
248    evas_object_geometry_get(sd->box, &x, NULL, &w, NULL);
249    elm_box_padding_get(sd->box, &hpad, &vpad);
250
251    line_num = 1;
252
253    if (sd->label && _label_packed(obj))
254      {
255         evas_object_size_hint_min_get(sd->label, &mnw, &mnh);
256
257         linew = mnw;
258         linew += hpad;
259         lineh = mnh;
260      }
261
262    EINA_LIST_FOREACH(sd->items, l, it)
263      {
264         if (it == except_it) continue;
265
266         evas_object_size_hint_min_get(VIEW(it), &mnw, &mnh);
267
268         linew += mnw;
269         if (lineh < mnh) lineh = mnh;
270
271         if (linew > w)
272           {
273              linew = mnw;
274              line_num++;
275           }
276
277
278         linew += hpad;
279      }
280
281    if (minh_wo_entry)
282      *minh_wo_entry = lineh * line_num + (line_num - 1) * vpad;
283
284    if (sd->editable)
285      {
286         // get entry size after text is reset
287         elm_object_text_set(sd->entry, "");
288         elm_layout_sizing_eval(sd->entry);
289         evas_object_size_hint_min_get(sd->entry, &mnw, &mnh);
290
291         linew += mnw;
292         if (lineh < mnh) lineh = mnh;
293
294         if (linew > w) line_num++;
295      }
296
297    if (minh)
298      *minh = lineh * line_num + (line_num - 1) * vpad;
299 }
300
301 static void
302 _on_item_expanding_transit_del(void *data,
303                                Elm_Transit *transit __UNUSED__)
304 {
305    Elm_Multibuttonentry_Item *it = data;
306
307    evas_object_data_set(VIEW(it), "transit", NULL);
308    evas_object_smart_callback_call(WIDGET(it), SIG_ITEM_ADDED, it);
309 }
310
311 static void
312 _after_rect_expand(Evas_Object *rect,
313                   Elm_Multibuttonentry_Item *it)
314 {
315    Eina_List *children;
316    Elm_Multibuttonentry_Item *last_item;
317
318    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
319
320    evas_object_del(rect);
321    evas_object_data_set(VIEW(it), "effect_rect", NULL);
322
323    // if last item is unpacked, add it
324    children = elm_box_children_get(sd->box);
325    last_item = eina_list_data_get(eina_list_last(sd->items));
326    if (VIEW(last_item) != eina_list_data_get(eina_list_last(children)))
327      {
328         elm_box_pack_end(sd->box, VIEW(last_item));
329         evas_object_show(VIEW(last_item));
330      }
331    eina_list_free(children);
332
333    if (sd->editable)
334      {
335         elm_box_pack_end(sd->box, sd->entry);
336         evas_object_show(sd->entry);
337         if (elm_object_focus_get(WIDGET(it)))
338           elm_object_focus_set(sd->entry, EINA_TRUE);
339      }
340 }
341
342 static Eina_Bool
343 _rect_expanding_animate(void *data)
344 {
345    Evas_Coord w, h, eh;
346    Evas_Object *rect;
347    Elm_Multibuttonentry_Item *it = data;
348
349    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
350
351    rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
352    if (!rect) return ECORE_CALLBACK_CANCEL;
353
354    evas_object_geometry_get(sd->entry, NULL, NULL, NULL, &eh);
355    evas_object_size_hint_min_get(rect, &w, &h);
356
357    if (h >= eh)
358      {
359         _after_rect_expand(rect, it);
360         return ECORE_CALLBACK_CANCEL;
361      }
362    else
363      evas_object_size_hint_min_set(rect, w, h + eh / ANIMATE_FRAME);
364
365    return ECORE_CALLBACK_RENEW;
366 }
367
368 static void
369 _item_adding_effect_add(Evas_Object *obj,
370                         Elm_Multibuttonentry_Item *it)
371 {
372    Elm_Transit *trans;
373    Evas_Coord minh_wo_entry, minh;
374    Eina_Bool floating = EINA_FALSE;;
375
376    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
377
378    _box_layout_pre_calculate(obj, NULL, &minh_wo_entry, &minh);
379
380    // if box will be expanded, add resizing effect
381    if (sd->boxh < minh)
382      {
383         Evas_Coord bx, by, bw, bh;
384         Evas_Object *rect;
385         Ecore_Animator *anim;
386
387         evas_object_geometry_get(sd->box, &bx, &by, &bw, &bh);
388
389         // if box will be expanded with item and entry
390         if (minh_wo_entry == minh)
391           {
392              Elm_Multibuttonentry_Item *last_it;
393
394              last_it = eina_list_data_get(eina_list_last(sd->items));
395              if (it == last_it)
396                {
397                   Evas_Coord iw, ih, vpad;
398
399                   evas_object_size_hint_min_get(VIEW(it), &iw, &ih);
400                   elm_box_padding_get(sd->box, NULL, &vpad);
401
402                   evas_object_move(VIEW(it), bx, by + bh + vpad);
403                   evas_object_resize(VIEW(it), iw, ih);
404                   evas_object_show(VIEW(it));
405
406                   floating = EINA_TRUE;
407                }
408              else
409                {
410                   elm_box_unpack(sd->box, VIEW(last_it));
411                   evas_object_hide(VIEW(last_it));
412                }
413           }
414
415         if (sd->editable)
416           {
417              if (elm_object_focus_get(sd->entry))
418                elm_object_focus_set(sd->entry, EINA_FALSE);
419              elm_box_unpack(sd->box, sd->entry);
420              evas_object_hide(sd->entry);
421              elm_entry_input_panel_show(sd->entry);
422           }
423
424         rect = evas_object_rectangle_add(evas_object_evas_get(obj));
425         evas_object_color_set(rect, 0, 0, 0, 0);
426 #ifdef _BOX_VI
427         evas_object_size_hint_min_set(rect, bw, 0);
428         evas_object_data_set(VIEW(it), "effect_rect", rect);
429         elm_box_pack_end(sd->box, rect);
430         evas_object_show(rect);
431
432         anim = ecore_animator_add(_rect_expanding_animate, it);
433         evas_object_data_set(rect, "animator", anim);
434 #else
435         Evas_Coord eh;
436         evas_object_geometry_get(sd->entry, NULL, NULL, NULL, &eh);
437
438         evas_object_size_hint_min_set(rect, bw, eh);
439         evas_object_data_set(VIEW(it), "effect_rect", rect);
440         elm_box_pack_end(sd->box, rect);
441         evas_object_show(rect);
442
443         _after_rect_expand(rect, it);
444
445 #endif
446      }
447
448    if (!floating)
449      {
450         Eina_List *cur;
451         cur = eina_list_data_find_list(sd->items, it);
452         if (cur == sd->items)
453           {
454              if (sd->label && _label_packed(obj))
455                elm_box_pack_after(sd->box, VIEW(it), sd->label);
456              else
457                elm_box_pack_start(sd->box, VIEW(it));
458           }
459         else
460           {
461              Elm_Multibuttonentry_Item *prev_it;
462              prev_it = eina_list_data_get(eina_list_prev(cur));
463              elm_box_pack_after(sd->box, VIEW(it), VIEW(prev_it));
464           }
465         evas_object_show(VIEW(it));
466      }
467
468    trans = elm_transit_add();
469    elm_transit_object_add(trans, VIEW(it));
470    elm_transit_effect_zoom_add(trans, 0.9, 1.0);
471    elm_transit_effect_color_add(trans, 0, 0, 0, 0, 255, 255, 255, 255);
472    elm_transit_del_cb_set(trans, _on_item_expanding_transit_del, it);
473    elm_transit_duration_set(trans, TRANSIT_DURATION);
474    evas_object_data_set(VIEW(it), "transit", trans);
475    elm_transit_go(trans);
476 }
477
478 static void
479 _on_item_contracting_transit_del(void *data,
480                                  Elm_Transit *transit __UNUSED__)
481 {
482    Evas_Object *rect;
483    Elm_Multibuttonentry_Item *it = data;
484
485    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
486
487    evas_object_data_set(VIEW(it), "transit", NULL);
488
489    rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
490    if (rect)
491      {
492         evas_object_hide(VIEW(it));
493         return;
494      }
495
496    // delete item and set focus to entry
497    if (sd->editable && elm_object_focus_get(WIDGET(it)))
498      elm_object_focus_set(sd->entry, EINA_TRUE);
499
500    elm_object_item_del((Elm_Object_Item *)it);
501 }
502
503 static void
504 _after_rect_contract(Evas_Object *rect,
505                           Elm_Multibuttonentry_Item *it)
506 {
507    Elm_Multibuttonentry_Item *last_item;
508
509    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
510
511    evas_object_del(rect);
512    evas_object_data_set(VIEW(it), "effect_rect", NULL);
513
514    // if last item is unpacked, add it
515    last_item = eina_list_data_get(eina_list_last(sd->items));
516    if (it != last_item)
517      {
518         if (!evas_object_visible_get(VIEW(last_item)))
519           {
520              elm_box_pack_end(sd->box, VIEW(last_item));
521              evas_object_show(VIEW(last_item));
522           }
523      }
524
525    if (sd->editable)
526      {
527         elm_box_pack_end(sd->box, sd->entry);
528         evas_object_show(sd->entry);
529         if (elm_object_focus_get(WIDGET(it)))
530           elm_object_focus_set(sd->entry, EINA_TRUE);
531      }
532 }
533
534 static Eina_Bool
535 _rect_contracting_animate(void *data)
536 {
537    Evas_Coord w, h, eh;
538    Evas_Object *rect;
539    Elm_Multibuttonentry_Item *it = data;
540
541    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
542
543    rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
544    if (!rect) return ECORE_CALLBACK_CANCEL;
545
546    evas_object_geometry_get(sd->entry, NULL, NULL, NULL, &eh);
547    evas_object_size_hint_min_get(rect, &w, &h);
548
549    if (h <= 0)
550      {
551         Elm_Transit *trans;
552         _after_rect_contract(rect, it);
553
554         // delete the button
555         trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
556         if (!trans)
557           _on_item_contracting_transit_del(it, NULL);
558
559         return ECORE_CALLBACK_CANCEL;
560      }
561    else
562      evas_object_size_hint_min_set(rect, w, h - eh / ANIMATE_FRAME);
563
564    return ECORE_CALLBACK_RENEW;
565 }
566
567 static void
568 _item_deleting_effect_add(Evas_Object *obj,
569                           Elm_Multibuttonentry_Item *it)
570 {
571    Elm_Transit *trans;
572    Evas_Coord minh;
573
574    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
575
576    _box_layout_pre_calculate(obj, it, NULL, &minh);
577
578    // if box will be contracted, add resizing effect
579    if (sd->boxh > minh)
580      {
581         Evas_Coord bx, bw, ix, eh;
582         Ecore_Animator *anim;
583         Evas_Object *rect;
584         Elm_Multibuttonentry_Item *last_it;
585
586         last_it = eina_list_data_get(eina_list_last(sd->items));
587         evas_object_geometry_get(sd->box, &bx, NULL, &bw, NULL);
588         evas_object_geometry_get(VIEW(last_it), &ix, NULL, NULL, NULL);
589
590         // if box will be contracted with item and entry
591         if (ix == bx)
592           {
593              if (it == last_it)
594                elm_box_unpack(sd->box, VIEW(it));
595              else
596                {
597                   elm_box_unpack(sd->box, VIEW(last_it));
598                   evas_object_hide(VIEW(last_it));
599                }
600           }
601
602         if (sd->editable)
603           {
604              if (elm_object_focus_get(sd->entry))
605                elm_object_focus_set(sd->entry, EINA_FALSE);
606              elm_box_unpack(sd->box, sd->entry);
607              evas_object_hide(sd->entry);
608              elm_entry_input_panel_show(sd->entry);
609           }
610
611         rect = evas_object_rectangle_add(evas_object_evas_get(obj));
612         evas_object_color_set(rect, 0, 0, 0, 0);
613 #ifdef _BOX_VI
614         evas_object_geometry_get(sd->entry, NULL, NULL, NULL, &eh);
615         evas_object_size_hint_min_set(rect, bw, eh);
616         evas_object_data_set(VIEW(it), "effect_rect", rect);
617         elm_box_pack_end(sd->box, rect);
618         evas_object_show(rect);
619
620         anim = ecore_animator_add(_rect_contracting_animate, it);
621         evas_object_data_set(rect, "animator", anim);
622 #else
623         evas_object_size_hint_min_set(rect, bw, 0);
624         evas_object_data_set(VIEW(it), "effect_rect", rect);
625         elm_box_pack_end(sd->box, rect);
626         evas_object_show(rect);
627
628         _after_rect_contract(rect, it);
629 #endif
630      }
631
632    trans = elm_transit_add();
633    elm_transit_object_add(trans, VIEW(it));
634    elm_transit_effect_zoom_add(trans, 1.0, 0.9);
635    elm_transit_effect_color_add(trans, 255, 255, 255, 255, 0, 0, 0, 0);
636    elm_transit_del_cb_set(trans, _on_item_contracting_transit_del, it);
637    elm_transit_duration_set(trans, TRANSIT_DURATION);
638    evas_object_data_set(VIEW(it), "transit", trans);
639    elm_transit_go(trans);
640
641 }
642 #endif
643
644 static void
645 _layout_expand(Evas_Object *obj)
646 {
647    int count, items_count, i;
648    Eina_List *children;
649    Elm_Multibuttonentry_Item *it;
650
651    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
652
653    if (!sd->items) return;
654    if (sd->expanded_state) return;
655
656    children = elm_box_children_get(sd->box);
657    count = eina_list_count(children);
658    if (sd->end)
659      {
660         evas_object_del(sd->end);
661         sd->end = NULL;
662         count--;
663      }
664    if (sd->label && _label_packed(obj)) count--;
665    eina_list_free(children);
666
667    items_count = eina_list_count(sd->items);
668    for (i = count; i < items_count; i++)
669      {
670         it = eina_list_nth(sd->items, i);
671         elm_box_pack_end(sd->box, VIEW(it));
672         evas_object_show(VIEW(it));
673      }
674
675    if (sd->editable)
676      {
677         elm_box_pack_end(sd->box, sd->entry);
678         evas_object_show(sd->entry);
679      }
680
681    sd->expanded_state = EINA_TRUE;
682    evas_object_smart_callback_call(obj, SIG_EXPAND_STATE_CHANGED, NULL);
683 }
684
685 static void
686 _layout_shrink(Evas_Object *obj,
687                Eina_Bool force)
688 {
689    Evas_Coord w, mnw, linew = 0, hpad = 0;
690    int count = 0, items_count, i;
691    Eina_List *l, *children;
692    Evas_Object *child;
693    Elm_Multibuttonentry_Item *it;
694 #ifdef _VI_EFFECT
695    Elm_Transit *trans;
696    Evas_Object *rect;
697    Ecore_Animator *anim;
698 #endif
699
700    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
701
702    if (!sd->items) return;
703    if (!sd->expanded_state && !force) return;
704
705    evas_object_geometry_get(sd->box, NULL, NULL, &w, NULL);
706    elm_box_padding_get(sd->box, &hpad, NULL);
707
708    if (sd->label && _label_packed(obj))
709      {
710         evas_object_size_hint_min_get(sd->label, &mnw, NULL);
711         linew += mnw;
712         linew += hpad;
713      }
714
715    EINA_LIST_FOREACH(sd->items, l, it)
716      {
717         evas_object_size_hint_min_get(VIEW(it), &mnw, NULL);
718         linew += mnw;
719
720         if (linew > w)
721           {
722              linew -= mnw;
723              break;
724           }
725
726         count++;
727         linew += hpad;
728      }
729
730    if (!count) return;
731
732    items_count = eina_list_count(sd->items);
733    if (count < items_count)
734      {
735         const char *str = NULL;
736         char buf[16];
737
738         str = elm_layout_data_get(obj, "closed_button_type");
739         if (!sd->end)
740           {
741              sd->end = elm_layout_add(obj);
742              if (str && !strcmp(str, "image"))
743                elm_layout_theme_set(sd->end, "multibuttonentry",
744                                     "closedbutton", elm_widget_style_get(obj));
745              else
746                elm_layout_theme_set(sd->end, "multibuttonentry",
747                                     "number", elm_widget_style_get(obj));
748           }
749         if (!str || strcmp(str, "image"))
750           {
751              snprintf(buf, sizeof(buf), "+%d", items_count - count);
752              elm_object_text_set(sd->end, buf);
753
754              // ACCESS
755              if (_elm_config->access_mode && sd->end)
756                {
757                   _elm_access_object_register(obj, ELM_WIDGET_DATA(sd)->resize_obj);
758                   _elm_access_callback_set(_elm_access_object_get(obj), ELM_ACCESS_INFO, _access_shrink_info_cb, obj);
759                }
760           }
761         evas_object_smart_calculate(sd->end);
762         evas_object_size_hint_min_get(sd->end, &mnw, NULL);
763         linew += mnw;
764
765         if (linew > w)
766           {
767              count--;
768              if (!str || strcmp(str, "image"))
769                {
770                   snprintf(buf, sizeof(buf), "+%d", items_count - count);
771                   elm_object_text_set(sd->end, buf);
772
773                   // ACCESS
774                   if (_elm_config->access_mode && sd->end)
775                    {
776                       _elm_access_object_register(obj, ELM_WIDGET_DATA(sd)->resize_obj);
777                       _elm_access_callback_set(_elm_access_object_get(obj), ELM_ACCESS_INFO, _access_shrink_info_cb, obj);
778                    }
779                }
780           }
781
782         if (!force)
783           {
784 #ifdef _VI_EFFECT
785              // reset last inserted item's effect_rect
786              it = eina_list_nth(sd->items, count - 1);
787              rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
788              if (rect)
789                {
790                   anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
791                   if (anim) ecore_animator_del(anim);
792
793                   evas_object_del(rect);
794                   evas_object_data_set(VIEW(it), "effect_rect", NULL);
795                }
796 #endif
797
798              for (i = count; i < items_count; i++)
799                {
800                   it = eina_list_nth(sd->items, i);
801 #ifdef _VI_EFFECT
802                   // reset all effects
803                   trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
804                   if (trans) elm_transit_del(trans);
805
806                   rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
807                   if (rect)
808                     {
809                        anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
810                        if (anim) ecore_animator_del(anim);
811
812                        evas_object_del(rect);
813                        evas_object_data_set(VIEW(it), "effect_rect", NULL);
814                     }
815 #endif
816                   elm_box_unpack(sd->box, VIEW(it));
817                   evas_object_hide(VIEW(it));
818                }
819
820              if (sd->editable)
821                {
822                   elm_box_unpack(sd->box, sd->entry);
823                   evas_object_hide(sd->entry);
824                }
825           }
826         else
827           {
828              // if it is called from item_append_xxx, item_del functions,
829              // all items are unpacked and packed again
830 #ifdef _VI_EFFECT
831              // reset last inserted item's effect_rect
832              it = eina_list_nth(sd->items, count - 1);
833              rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
834              if (rect)
835                {
836                   anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
837                   if (anim) ecore_animator_del(anim);
838
839                   evas_object_del(rect);
840                   evas_object_data_set(VIEW(it), "effect_rect", NULL);
841                }
842
843              for (i = count; i < items_count; i++)
844                {
845                   it = eina_list_nth(sd->items, i);
846                   // reset all effects
847                   trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
848                   if (trans) elm_transit_del(trans);
849
850                   rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
851                   if (rect)
852                     {
853                        anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
854                        if (anim) ecore_animator_del(anim);
855
856                        evas_object_del(rect);
857                        evas_object_data_set(VIEW(it), "effect_rect", NULL);
858                     }
859                }
860 #endif
861
862              children = elm_box_children_get(sd->box);
863              EINA_LIST_FREE(children, child)
864                {
865                   if (child != sd->label)
866                     {
867                        elm_box_unpack(sd->box, child);
868                        evas_object_hide(child);
869                     }
870                }
871
872              for (i = 0; i < count; i++)
873                {
874                   it = eina_list_nth(sd->items, i);
875                   elm_box_pack_end(sd->box, VIEW(it));
876                   evas_object_show(VIEW(it));
877                }
878           }
879
880         elm_box_pack_end(sd->box, sd->end);
881         evas_object_show(sd->end);
882
883         sd->expanded_state = EINA_FALSE;
884      }
885    else
886      {
887         if (!force)
888           {
889 #ifdef _VI_EFFECT
890              // reset last inserted item's effect_rect
891              it = eina_list_nth(sd->items, count - 1);
892              rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
893              if (rect)
894                {
895                   anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
896                   if (anim) ecore_animator_del(anim);
897
898                   evas_object_del(rect);
899                   evas_object_data_set(VIEW(it), "effect_rect", NULL);
900
901                   if (sd->editable)
902                     {
903                        elm_box_pack_end(sd->box, sd->entry);
904                        evas_object_show(sd->entry);
905                        if (elm_object_focus_get(WIDGET(it)))
906                          elm_object_focus_set(sd->entry, EINA_TRUE);
907                     }
908                }
909 #endif
910              if (sd->editable)
911                {
912                   evas_object_size_hint_min_get(sd->entry, &mnw, NULL);
913                   linew += mnw;
914                   if (linew > (w * (2 / 3)))
915                     {
916                        elm_box_unpack(sd->box, sd->entry);
917                        evas_object_hide(sd->entry);
918                        sd->expanded_state = EINA_FALSE;
919                     }
920                }
921           }
922         else
923           {
924              if (sd->end)
925                {
926                   evas_object_del(sd->end);
927                   sd->end = NULL;
928                }
929
930              // if it is called from item_append_xxx, item_del functions,
931              // all items are unpacked and packed again
932 #ifdef _VI_EFFECT
933              // reset last inserted item's effect_rect
934              it = eina_list_nth(sd->items, count - 1);
935              rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
936              if (rect)
937                {
938                   anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
939                   if (anim) ecore_animator_del(anim);
940
941                   evas_object_del(rect);
942                   evas_object_data_set(VIEW(it), "effect_rect", NULL);
943                }
944 #endif
945
946              children = elm_box_children_get(sd->box);
947              EINA_LIST_FREE(children, child)
948                {
949                   if (child != sd->label)
950                     {
951                        elm_box_unpack(sd->box, child);
952                        evas_object_hide(child);
953                     }
954                }
955
956              for (i = 0; i < count; i++)
957                {
958                   it = eina_list_nth(sd->items, i);
959                   elm_box_pack_end(sd->box, VIEW(it));
960                   evas_object_show(VIEW(it));
961                }
962
963              sd->expanded_state = EINA_TRUE;
964
965              if (sd->editable)
966                {
967                   evas_object_size_hint_min_get(sd->entry, &mnw, NULL);
968                   linew += mnw;
969                   if (linew > w)
970                     sd->expanded_state = EINA_FALSE;
971                   else
972                     {
973                        elm_box_pack_end(sd->box, sd->entry);
974                        evas_object_show(sd->entry);
975                     }
976                }
977           }
978      }
979
980    if (!sd->expanded_state && !force)
981      evas_object_smart_callback_call(obj, SIG_EXPAND_STATE_CHANGED, NULL);
982 }
983
984 static Eina_Bool
985 _box_min_size_calculate(Evas_Object *box,
986                         Evas_Object_Box_Data *priv,
987                         int *line_height,
988                         void *data)
989 {
990    Evas_Coord mnw, mnh, w, minw, minh = 0, linew = 0, lineh = 0;
991    int line_num;
992    Eina_List *l;
993    Evas_Object_Box_Option *opt;
994
995    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
996
997    evas_object_geometry_get(box, NULL, NULL, &w, NULL);
998    evas_object_size_hint_min_get(box, &minw, NULL);
999    if (!w) return EINA_FALSE;
1000
1001    line_num = 1;
1002    EINA_LIST_FOREACH(priv->children, l, opt)
1003      {
1004         evas_object_size_hint_min_get(opt->obj, &mnw, &mnh);
1005
1006 #ifdef _VI_EFFECT
1007         if (mnw == w &&
1008             !strcmp(evas_object_type_get(opt->obj), "rectangle"))
1009           break;
1010 #endif
1011
1012         linew += mnw;
1013         if (lineh < mnh) lineh = mnh;
1014
1015         if (linew > w)
1016           {
1017              linew = mnw;
1018              line_num++;
1019           }
1020         else if (linew > w * 2 / 3)
1021           {
1022              // if linew is larger than 2/3 of boxw, box should be larger.
1023              linew = 0;
1024              line_num++;
1025              // whether there is "+%d" at the end of the box or entry is invisible,
1026              // box doesn't have to be larger.
1027              if (sd->end || !evas_object_visible_get(sd->entry))
1028                line_num--;
1029           }
1030
1031         if (l != eina_list_last(priv->children))
1032           linew += priv->pad.h;
1033      }
1034
1035    minh = lineh * line_num + (line_num - 1) * priv->pad.v;
1036
1037 #ifdef _VI_EFFECT
1038    // if last item is effect_rect
1039    if (opt && opt->obj && mnw == w &&
1040        !strcmp(evas_object_type_get(opt->obj), "rectangle"))
1041      {
1042         minh += priv->pad.v;
1043         minh += mnh;
1044      }
1045 #endif
1046
1047    evas_object_size_hint_min_set(box, minw, minh);
1048    *line_height = lineh;
1049
1050    return EINA_TRUE;
1051 }
1052
1053 static void
1054 _box_layout(Evas_Object *o,
1055             Evas_Object_Box_Data *priv,
1056             void *data)
1057 {
1058    Evas_Coord x, y, w, h, xx, yy, xxx, yyy;
1059    Evas_Coord minw, minh, linew = 0, lineh = 0, lineww = 0;
1060    double ax, ay;
1061    Eina_Bool rtl;
1062    Eina_List *l;
1063    Evas_Object *obj;
1064    Evas_Object_Box_Option *opt;
1065
1066    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
1067
1068    if (!_box_min_size_calculate(o, priv, &lineh, data)) return;
1069
1070    evas_object_geometry_get(o, &x, &y, &w, &h);
1071    evas_object_size_hint_min_get(o, &minw, &minh);
1072    evas_object_size_hint_align_get(o, &ax, &ay);
1073
1074    rtl = elm_widget_mirrored_get(data);
1075    if (rtl) ax = 1.0 - ax;
1076
1077    if (w < minw)
1078      {
1079         x = x + ((w - minw) * (1.0 - ax));
1080         w = minw;
1081      }
1082    if (h < minh)
1083      {
1084         y = y + ((h - minh) * (1.0 - ay));
1085         h = minh;
1086      }
1087
1088    xx = x;
1089    yy = y;
1090    EINA_LIST_FOREACH(priv->children, l, opt)
1091      {
1092         Evas_Coord mnw, mnh, ww, hh, ow, oh;
1093         double wx, wy;
1094         Eina_Bool fw, fh, xw, xh;
1095
1096         obj = opt->obj;
1097         evas_object_size_hint_align_get(obj, &ax, &ay);
1098         evas_object_size_hint_weight_get(obj, &wx, &wy);
1099         evas_object_size_hint_min_get(obj, &mnw, &mnh);
1100
1101         fw = fh = EINA_FALSE;
1102         xw = xh = EINA_FALSE;
1103         if (ax == -1.0) {fw = EINA_TRUE; ax = 0.5;}
1104         if (ay == -1.0) {fh = EINA_TRUE; ay = 0.5;}
1105         if (rtl) ax = 1.0 - ax;
1106         if (wx > 0.0) xw = EINA_TRUE;
1107         if (wy > 0.0) xh = EINA_TRUE;
1108
1109         ww = mnw;
1110         if (xw)
1111           {
1112              if (ww <= w - linew) ww = w - linew;
1113              else ww = w;
1114           }
1115         hh = lineh;
1116
1117         ow = mnw;
1118         if (fw) ow = ww;
1119         oh = mnh;
1120         if (fh) oh = hh;
1121
1122         linew += ww;
1123         if (linew > w && l != priv->children)
1124           {
1125              xx = x;
1126              yy += hh;
1127              yy += priv->pad.v;
1128              linew = ww;
1129           }
1130         linew += priv->pad.h;
1131
1132         evas_object_move(obj,
1133                          ((!rtl) ? (xx) : (x + (w - (xx - x) - ww)))
1134                          + (Evas_Coord)(((double)(ww - ow)) * ax),
1135                          yy + (Evas_Coord)(((double)(hh - oh)) * ay));
1136         evas_object_resize(obj, ow, oh);
1137
1138         xx += ww;
1139         xx += priv->pad.h;
1140         xxx = xx;
1141         yyy = yy;
1142         lineww = linew;
1143
1144         // if linew is bigger than 2/3 of boxw, entry goes to next line.
1145         if (linew > w * 2 / 3)
1146           {
1147              xx = x;
1148              yy += hh;
1149              yy += priv->pad.v;
1150              linew = 0;
1151           }
1152
1153         // whether there is "+%d" at the end of the box or entry is invisible,
1154         // box doesn't have to be larger.
1155         if (sd->end || !evas_object_visible_get(sd->entry))
1156           {
1157              xx = xxx;
1158              yy = yyy;
1159              linew = lineww;
1160           }
1161      }
1162 }
1163
1164 static void
1165 _on_box_resize(void *data,
1166                Evas *e __UNUSED__,
1167                Evas_Object *obj,
1168                void *event_info __UNUSED__)
1169 {
1170    Evas_Coord w, h;
1171
1172    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
1173
1174    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1175
1176    if (sd->boxh < h)
1177      evas_object_smart_callback_call(data, SIG_EXPANDED, NULL);
1178    else if (sd->boxh > h)
1179      evas_object_smart_callback_call(data, SIG_CONTRACTED, NULL);
1180
1181    // on rotation, items should be packed again in the shrinked layout
1182    if (sd->boxw && sd->boxw != w)
1183      {
1184         if (!elm_object_focus_get(data) && !sd->expanded)
1185           _layout_shrink(data, EINA_TRUE);
1186      }
1187
1188    sd->boxh = h;
1189    sd->boxw = w;
1190 }
1191
1192 static Elm_Multibuttonentry_Item_Filter *
1193 _filter_new(Elm_Multibuttonentry_Item_Filter_Cb func,
1194             const void *data)
1195 {
1196    Elm_Multibuttonentry_Item_Filter *ft;
1197
1198    ft = ELM_NEW(Elm_Multibuttonentry_Item_Filter);
1199    if (!ft) return NULL;
1200
1201    ft->func = func;
1202    ft->data = data;
1203
1204    return ft;
1205 }
1206
1207 static void
1208 _on_item_clicked(void *data,
1209                  Evas_Object *obj __UNUSED__,
1210                  const char *emission __UNUSED__,
1211                  const char *source __UNUSED__)
1212 {
1213    Elm_Multibuttonentry_Item *it = data;
1214
1215    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1216
1217    evas_object_focus_set(elm_layout_edje_get(VIEW(it)), EINA_TRUE);
1218
1219    // handles input panel because it can be hidden by user
1220    if (sd->editable)
1221      elm_entry_input_panel_show(sd->entry);
1222
1223    evas_object_smart_callback_call(WIDGET(it), SIG_ITEM_CLICKED, it);
1224 }
1225
1226 static void
1227 _on_item_selected(void *data,
1228                   Evas_Object *obj __UNUSED__,
1229                   const char *emission __UNUSED__,
1230                   const char *source __UNUSED__)
1231 {
1232    Elm_Multibuttonentry_Item *it = data;
1233
1234    if (it->func) it->func((void *)it->base.data, WIDGET(it), it);
1235
1236    evas_object_smart_callback_call(WIDGET(it), SIG_ITEM_SELECTED, it);
1237 }
1238
1239 static void
1240 _on_item_focus(void *data,
1241                Evas *e __UNUSED__,
1242                Evas_Object *obj,
1243                void *event_info __UNUSED__)
1244 {
1245    Elm_Multibuttonentry_Item *it = data;
1246
1247    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1248
1249    if (evas_object_focus_get(obj))
1250      {
1251         if (elm_object_focus_get(sd->entry))
1252           elm_object_focus_set(sd->entry, EINA_FALSE);
1253
1254         sd->selected_item = (Elm_Object_Item *)it;
1255         elm_layout_signal_emit(VIEW(it), "focused", "");
1256
1257         if (sd->editable)
1258           elm_entry_input_panel_show(sd->entry);
1259      }
1260    else
1261      {
1262         sd->selected_item = NULL;
1263         elm_layout_signal_emit(VIEW(it), "default", "");
1264
1265         if (sd->editable)
1266           elm_entry_input_panel_hide(sd->entry);
1267      }
1268 }
1269
1270 static Eina_Bool
1271 _long_press_cb(void *data)
1272 {
1273    Elm_Multibuttonentry_Item *it = data;
1274
1275    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1276
1277    sd->longpress_timer = NULL;
1278    sd->long_pressed = EINA_TRUE;
1279
1280    evas_object_smart_callback_call(WIDGET(it), SIG_LONGPRESSED, it);
1281
1282    return ECORE_CALLBACK_CANCEL;
1283 }
1284
1285 static void
1286 _mouse_down_cb(Elm_Multibuttonentry_Item *it,
1287                Evas *evas __UNUSED__,
1288                Evas_Object *obj __UNUSED__,
1289                Evas_Event_Mouse_Down *ev)
1290 {
1291    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1292
1293    if (ev->button != 1) return;
1294
1295    sd->long_pressed = EINA_FALSE;
1296
1297    if (sd->longpress_timer) ecore_timer_del(sd->longpress_timer);
1298    sd->longpress_timer = ecore_timer_add
1299        (_elm_config->longpress_timeout, _long_press_cb, it);
1300 }
1301
1302 static void
1303 _mouse_up_cb(Elm_Multibuttonentry_Item *it,
1304              Evas *evas __UNUSED__,
1305              Evas_Object *obj __UNUSED__,
1306              Evas_Event_Mouse_Down *ev __UNUSED__)
1307 {
1308    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1309
1310    if (sd->longpress_timer)
1311      {
1312         ecore_timer_del(sd->longpress_timer);
1313         sd->longpress_timer = NULL;
1314      }
1315 }
1316
1317 static void
1318 _item_text_set_hook(Elm_Object_Item *it,
1319                     const char *part,
1320                     const char *text)
1321 {
1322    if (part && strcmp(part, "elm.btn.text")) return;
1323    if (!text) return;
1324
1325    elm_object_part_text_set(VIEW(it), "elm.btn.text", text);
1326 }
1327
1328 static const char *
1329 _item_text_get_hook(const Elm_Object_Item *it,
1330                     const char *part)
1331 {
1332    if (part && strcmp(part, "elm.btn.text")) return NULL;
1333
1334    return elm_object_part_text_get(VIEW(it), "elm.btn.text");
1335 }
1336
1337 static Eina_Bool
1338 _item_del_pre_hook(Elm_Object_Item *it)
1339 {
1340    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
1341
1342    sd->items = eina_list_remove(sd->items, it);
1343
1344    if (!elm_object_focus_get(WIDGET(it)) && !sd->expanded)
1345      _layout_shrink(WIDGET(it), EINA_TRUE);
1346
1347 #ifdef _VI_EFFECT
1348    Elm_Transit *trans;
1349    Evas_Object *rect;
1350
1351    trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
1352    if (trans)
1353      {
1354         elm_transit_del_cb_set(trans, NULL, NULL);
1355         elm_transit_del(trans);
1356      }
1357
1358    rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
1359    if (rect)
1360      {
1361         Ecore_Animator *anim;
1362         anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
1363         if (anim) ecore_animator_del(anim);
1364
1365         evas_object_del(rect);
1366         evas_object_data_set(VIEW(it), "effect_rect", NULL);
1367
1368         if (sd->editable)
1369           {
1370              elm_box_pack_end(sd->box, sd->entry);
1371              evas_object_show(sd->entry);
1372              if (elm_object_focus_get(WIDGET(it)))
1373                elm_object_focus_set(sd->entry, EINA_TRUE);
1374           }
1375      }
1376 #endif
1377
1378    if (!sd->items && !elm_object_focus_get(WIDGET(it)) &&
1379        sd->guide && !_guide_packed(WIDGET(it)))
1380      {
1381         if (sd->editable)
1382           {
1383              elm_box_unpack(sd->box, sd->entry);
1384              evas_object_hide(sd->entry);
1385           }
1386
1387         elm_box_pack_end(sd->box, sd->guide);
1388         evas_object_show(sd->guide);
1389      }
1390
1391    evas_object_smart_callback_call(WIDGET(it), SIG_ITEM_DELETED, it);
1392
1393    return EINA_TRUE;
1394 }
1395
1396 static char *
1397 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
1398 {
1399    Elm_Multibuttonentry_Item *it = (Elm_Multibuttonentry_Item *)data;
1400    const char *txt = NULL;
1401    Eina_Strbuf *buf = NULL;
1402    char *str = NULL;
1403
1404    if (!it) return NULL;
1405
1406    if (!txt)txt = elm_object_item_text_get((Elm_Object_Item *)it);
1407    if (txt)
1408      {
1409         buf = eina_strbuf_new();
1410         eina_strbuf_append(buf, E_(" double tap to edit"));
1411         eina_strbuf_prepend(buf, txt);
1412         str = eina_strbuf_string_steal(buf);
1413         eina_strbuf_free(buf);
1414         return str;
1415      }
1416
1417    return NULL;
1418 }
1419
1420 static char *
1421 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
1422 {
1423    Elm_Multibuttonentry_Item *it = (Elm_Multibuttonentry_Item *)data;
1424    if (!it) return NULL;
1425
1426    if (it->base.disabled)
1427      return strdup(E_("State: Disabled"));
1428
1429    return NULL;
1430 }
1431
1432 static void
1433 _access_activate_cb(void *data __UNUSED__,
1434                     Evas_Object *part_obj __UNUSED__,
1435                     Elm_Object_Item *item)
1436 {
1437    _on_item_selected(item, NULL, NULL, NULL);
1438 }
1439
1440 static void
1441 _access_widget_item_register(Elm_Multibuttonentry_Item *it, Eina_Bool is_access)
1442 {
1443    Elm_Access_Info *ai;
1444
1445    if (!is_access) _elm_access_widget_item_unregister((Elm_Widget_Item *)it);
1446    else
1447      {
1448         _elm_access_widget_item_register((Elm_Widget_Item *)it);
1449
1450         ai = _elm_access_object_get(it->base.access_obj);
1451
1452         _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
1453         _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, it);
1454         _elm_access_activate_callback_set(ai, _access_activate_cb, it);
1455      }
1456 }
1457
1458 static Elm_Multibuttonentry_Item *
1459 _item_new(Evas_Object *obj,
1460           const char *text,
1461           Evas_Smart_Cb func,
1462           const void *data)
1463 {
1464    Elm_Multibuttonentry_Item *it;
1465    Elm_Multibuttonentry_Item_Filter *ft;
1466    Eina_List *l;
1467    const char *str;
1468    Evas_Coord minw, minh, maxw = 0;
1469
1470    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1471
1472    EINA_LIST_FOREACH(sd->filters, l, ft)
1473      {
1474         if (!ft->func(obj, text, data, ft->data))
1475           return NULL;
1476      }
1477
1478    it = elm_widget_item_new(obj, Elm_Multibuttonentry_Item);
1479    if (!it) return NULL;
1480
1481    VIEW(it) = elm_layout_add(obj);
1482    elm_layout_theme_set
1483       (VIEW(it), "multibuttonentry", "btn", elm_widget_style_get(obj));
1484    elm_layout_signal_callback_add
1485       (VIEW(it), "elm,action,clicked", "", _on_item_clicked, it);
1486    elm_layout_signal_callback_add
1487       (VIEW(it), "elm,action,selected", "", _on_item_selected, it);
1488    evas_object_event_callback_add
1489       (elm_layout_edje_get(VIEW(it)),
1490        EVAS_CALLBACK_FOCUS_IN, _on_item_focus, it);
1491    evas_object_event_callback_add
1492       (elm_layout_edje_get(VIEW(it)),
1493        EVAS_CALLBACK_FOCUS_OUT, _on_item_focus, it);
1494    evas_object_event_callback_add
1495       (elm_layout_edje_get(VIEW(it)),
1496        EVAS_CALLBACK_MOUSE_DOWN, (Evas_Object_Event_Cb)_mouse_down_cb, it);
1497    evas_object_event_callback_add
1498       (elm_layout_edje_get(VIEW(it)),
1499        EVAS_CALLBACK_MOUSE_UP, (Evas_Object_Event_Cb)_mouse_up_cb, it);
1500    elm_object_part_text_set(VIEW(it), "elm.btn.text", text);
1501
1502    it->func = func;
1503    it->base.data = data;
1504
1505    // adjust item size if item is longer than maximum size
1506    evas_object_smart_calculate(VIEW(it));
1507    evas_object_size_hint_min_get(VIEW(it), &minw, &minh);
1508    str = elm_layout_data_get(VIEW(it), "button_max_size");
1509    if (str) maxw = atoi(str);
1510    maxw = maxw * elm_widget_scale_get(obj) * elm_config_scale_get();
1511    if (minw > maxw)
1512      {
1513         elm_layout_signal_emit(VIEW(it), "elm,state,text,ellipsis", "");
1514         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1515         evas_object_size_hint_min_set(VIEW(it), maxw, minh);
1516         elm_layout_sizing_eval(VIEW(it));
1517      }
1518
1519    elm_widget_item_text_set_hook_set(it, _item_text_set_hook);
1520    elm_widget_item_text_get_hook_set(it, _item_text_get_hook);
1521    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
1522
1523    sd->item_be_selected = EINA_TRUE;
1524
1525    // ACCESS
1526    if (_elm_config->access_mode) _access_widget_item_register(it, EINA_TRUE);
1527
1528    return it;
1529 }
1530
1531 static void
1532 _on_entry_unfocused(void *data,
1533                     Evas_Object *obj,
1534                     void *event_info __UNUSED__)
1535 {
1536    char *str;
1537
1538    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
1539
1540    str = elm_entry_markup_to_utf8(elm_object_text_get(obj));
1541    if (strlen(str))
1542      {
1543         Elm_Multibuttonentry_Item *it;
1544
1545         it = _item_new(data, str, NULL, NULL);
1546         if (!it) return;
1547
1548         sd->items = eina_list_append(sd->items, it);
1549 #ifdef _VI_EFFECT
1550         _item_adding_effect_add(data, it);
1551 #else
1552         elm_box_pack_before(sd->box, VIEW(it), obj);
1553         evas_object_show(VIEW(it));
1554         evas_object_smart_callback_call(data, SIG_ITEM_ADDED, it);
1555 #endif
1556
1557         elm_object_text_set(obj, "");
1558      }
1559    free(str);
1560 }
1561
1562 // handles semicolon, comma (before inserting them to the entry)
1563 static void
1564 _entry_filter(void *data,
1565               Evas_Object *entry,
1566               char **text)
1567 {
1568    char *str;
1569
1570    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
1571
1572    if (!*text || !strlen(*text)) return;
1573
1574    // cancels item_be_selected when text inserting is started
1575    if (strcmp(*text, ";") && strcmp(*text, ","))
1576      {
1577         sd->item_be_selected = EINA_FALSE;
1578         return;
1579      }
1580
1581    str = elm_entry_markup_to_utf8(elm_object_text_get(entry));
1582    if (strlen(str))
1583      {
1584         Elm_Multibuttonentry_Item *it;
1585
1586         it = _item_new(data, str, NULL, NULL);
1587         if (!it) return;
1588
1589         sd->items = eina_list_append(sd->items, it);
1590 #ifdef _VI_EFFECT
1591         _item_adding_effect_add(data, it);
1592 #else
1593         elm_box_pack_before(sd->box, VIEW(it), entry);
1594         evas_object_show(VIEW(it));
1595         evas_object_smart_callback_call(data, SIG_ITEM_ADDED, it);
1596 #endif
1597
1598         elm_object_text_set(entry, "");
1599      }
1600    free(str);
1601
1602    free(*text);
1603    *text = NULL;
1604 }
1605
1606 // handles enter key
1607 static void
1608 _on_entry_key_down(void *data,
1609                  Evas *e __UNUSED__,
1610                  Evas_Object *obj,
1611                  void *event_info)
1612 {
1613    char *str;
1614    Evas_Event_Key_Up *ev = (Evas_Event_Key_Up *)event_info;
1615
1616    ELM_MULTIBUTTONENTRY_DATA_GET(data, sd);
1617
1618    // cancels item_be_selected when text inserting is started
1619    if (strcmp(ev->keyname, "KP_Enter") && strcmp(ev->keyname, "Return") &&
1620        strcmp(ev->keyname, "BackSpace") && strcmp(ev->keyname, "Delete") &&
1621        strcmp(ev->keyname, "semicolon") && strcmp(ev->keyname, "comma"))
1622      {
1623         sd->item_be_selected = EINA_FALSE;
1624         return;
1625      }
1626
1627    if (!strcmp(ev->keyname, "KP_Enter") || !strcmp(ev->keyname, "Return"))
1628      {
1629         str = elm_entry_markup_to_utf8(elm_object_text_get(obj));
1630         if (strlen(str))
1631           {
1632              Elm_Multibuttonentry_Item *it;
1633
1634              it = _item_new(data, str, NULL, NULL);
1635              if (!it) return;
1636
1637              sd->items = eina_list_append(sd->items, it);
1638 #ifdef _VI_EFFECT
1639              _item_adding_effect_add(data, it);
1640 #else
1641              elm_box_pack_before(sd->box, VIEW(it), obj);
1642              evas_object_show(VIEW(it));
1643              evas_object_smart_callback_call(data, SIG_ITEM_ADDED, it);
1644 #endif
1645
1646              elm_object_text_set(obj, "");
1647           }
1648         free(str);
1649      }
1650 }
1651
1652 // handles delete key
1653 // it can be pressed when button is selected, so it is handled on layout_key_down
1654 static void
1655 _on_layout_key_down(void *data __UNUSED__,
1656                   Evas *e __UNUSED__,
1657                   Evas_Object *obj,
1658                   void *event_info)
1659 {
1660    char *str;
1661    Evas_Event_Key_Up *ev = (Evas_Event_Key_Up *)event_info;
1662
1663    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1664
1665    if (strcmp(ev->keyname, "BackSpace") && strcmp(ev->keyname, "Delete"))
1666      return;
1667
1668    str = elm_entry_markup_to_utf8(elm_object_text_get(sd->entry));
1669    if (strlen(str))
1670      {
1671         free(str);
1672         return;
1673      }
1674    free(str);
1675
1676    if (!sd->items) return;
1677
1678    if (!sd->selected_item)
1679      {
1680         if (sd->item_be_selected) // 2nd delete
1681           {
1682              Elm_Multibuttonentry_Item *it;
1683
1684              it = eina_list_data_get(eina_list_last(sd->items));
1685              evas_object_focus_set(elm_layout_edje_get(VIEW(it)), EINA_TRUE);
1686           }
1687         else // 1st delete
1688           sd->item_be_selected = EINA_TRUE;
1689      }
1690    else // 3rd delete
1691      {
1692 #ifdef _VI_EFFECT
1693         Elm_Transit *trans;
1694         Evas_Object *rect;
1695
1696         trans = (Elm_Transit *)evas_object_data_get(VIEW(sd->selected_item), "transit");
1697         rect = (Evas_Object *)evas_object_data_get(VIEW(sd->selected_item), "effect_rect");
1698
1699         if (!trans && !rect)
1700           _item_deleting_effect_add
1701              (obj, (Elm_Multibuttonentry_Item *)sd->selected_item);
1702 #else
1703         elm_object_item_del(sd->selected_item);
1704
1705         if (sd->editable)
1706           elm_object_focus_set(sd->entry, EINA_TRUE);
1707 #endif
1708      }
1709 }
1710
1711 static void
1712 _on_layout_clicked(void *data __UNUSED__,
1713                    Evas_Object *obj,
1714                    const char *emission __UNUSED__,
1715                    const char *source __UNUSED__)
1716 {
1717    evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
1718 }
1719
1720 static Eina_Bool
1721 _elm_multibuttonentry_smart_on_focus(Evas_Object *obj)
1722 {
1723    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1724
1725    if (!ELM_WIDGET_CLASS(_elm_multibuttonentry_parent_sc)->on_focus(obj))
1726      return EINA_FALSE;
1727
1728    if (elm_object_focus_get(obj))
1729      {
1730         // ACCESS
1731         //if ((_elm_config->access_mode == ELM_ACCESS_MODE_ON)) return EINA_TRUE;
1732
1733         if (sd->guide && _guide_packed(obj))
1734           {
1735              elm_box_unpack(sd->box, sd->guide);
1736              evas_object_hide(sd->guide);
1737
1738              if (sd->editable)
1739                {
1740                   elm_box_pack_end(sd->box, sd->entry);
1741                   evas_object_show(sd->entry);
1742                }
1743           }
1744         // when object gets focused, it should be expanded layout
1745         else if (!sd->expanded)
1746           _layout_expand(obj);
1747
1748         if (sd->editable)
1749           {
1750              elm_layout_signal_emit(obj, "elm,state,event,allow", "");
1751              elm_object_focus_set(sd->entry, EINA_TRUE);
1752           }
1753
1754         evas_object_smart_callback_call(obj, SIG_FOCUSED, NULL);
1755      }
1756    else
1757      {
1758         if (!sd->items && sd->guide)
1759           {
1760              if (sd->editable)
1761                {
1762                   elm_box_unpack(sd->box, sd->entry);
1763                   evas_object_hide(sd->entry);
1764                }
1765
1766              elm_box_pack_end(sd->box, sd->guide);
1767              evas_object_show(sd->guide);
1768           }
1769         // if shrinked mode was set, it goes back to shrinked layout
1770         else if (!sd->expanded)
1771           _layout_shrink(obj, EINA_FALSE);
1772
1773         if (sd->editable)
1774           elm_layout_signal_emit(obj, "elm,state,event,block", "");
1775
1776         if (sd->selected_item)
1777           evas_object_focus_set
1778              (elm_layout_edje_get(VIEW(sd->selected_item)), EINA_FALSE);
1779
1780         evas_object_smart_callback_call(obj, SIG_UNFOCUSED, NULL);
1781      }
1782
1783    return EINA_TRUE;
1784 }
1785
1786 static Eina_Bool
1787 _elm_multibuttonentry_smart_text_set(Evas_Object *obj,
1788                                      const char *part,
1789                                      const char *text)
1790 {
1791    if (!part || (part && !strcmp(part, "label")))
1792      {
1793         if (text) _label_set(obj, text);
1794         return EINA_TRUE;
1795      }
1796    else if (part && !strcmp(part, "guide"))
1797      {
1798         if (text) _guide_set(obj, text);
1799         return EINA_TRUE;
1800      }
1801    else return _elm_multibuttonentry_parent_sc->text_set(obj, part, text);
1802 }
1803
1804 static const char *
1805 _elm_multibuttonentry_smart_text_get(const Evas_Object *obj,
1806                                      const char *part)
1807 {
1808    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1809
1810    if (!part || !strcmp(part, "label"))
1811      return elm_object_part_text_get(sd->label, "mbe.label");
1812    else if (!strcmp(part, "guide"))
1813      return elm_object_text_get(sd->guide);
1814    else return _elm_multibuttonentry_parent_sc->text_get(obj, part);
1815 }
1816
1817 static void
1818 _elm_multibuttonentry_smart_sizing_eval(Evas_Object *obj)
1819 {
1820    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
1821
1822    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1823
1824    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
1825    edje_object_size_min_restricted_calc
1826       (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh, minw, minh);
1827    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
1828    evas_object_size_hint_min_set(obj, minw, minh);
1829    evas_object_size_hint_max_set(obj, maxw, maxh);
1830 }
1831
1832 static Eina_Bool
1833 _elm_multibuttonentry_smart_theme(Evas_Object *obj)
1834 {
1835    const char *str;
1836    int hpad = 0, vpad = 0;
1837    Eina_List *l;
1838    Elm_Multibuttonentry_Item *it;
1839
1840    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1841
1842    if (!ELM_WIDGET_CLASS(_elm_multibuttonentry_parent_sc)->theme(obj))
1843      return EINA_FALSE;
1844
1845    str = elm_layout_data_get(obj, "horizontal_pad");
1846    if (str) hpad = atoi(str);
1847    str = elm_layout_data_get(obj, "vertical_pad");
1848    if (str) vpad = atoi(str);
1849    elm_box_padding_set
1850       (sd->box,
1851        hpad * elm_widget_scale_get(obj) * elm_config_scale_get(),
1852        vpad * elm_widget_scale_get(obj) * elm_config_scale_get());
1853
1854    elm_layout_theme_set
1855       (sd->label, "multibuttonentry", "label", elm_widget_style_get(obj));
1856    elm_layout_theme_set
1857       (sd->guide, "multibuttonentry", "guidetext", elm_widget_style_get(obj));
1858    elm_layout_theme_set
1859       (sd->end, "multibuttonentry", "number", elm_widget_style_get(obj));
1860    EINA_LIST_FOREACH(sd->items, l, it)
1861       elm_layout_theme_set
1862       (VIEW(it), "multibuttonentry", "btn", elm_widget_style_get(obj));
1863
1864    elm_layout_sizing_eval(obj);
1865
1866    return EINA_TRUE;
1867 }
1868
1869 static void
1870 _elm_multibuttonentry_smart_add(Evas_Object *obj)
1871 {
1872    const char *str;
1873    int hpad = 0, vpad = 0;
1874
1875    EVAS_SMART_DATA_ALLOC(obj, Elm_Multibuttonentry_Smart_Data);
1876
1877    ELM_WIDGET_CLASS(_elm_multibuttonentry_parent_sc)->base.add(obj);
1878    elm_layout_theme_set
1879       (obj, "multibuttonentry", "base", elm_widget_style_get(obj));
1880    elm_layout_signal_callback_add
1881       (obj, "elm,action,clicked", "", _on_layout_clicked, NULL);
1882    evas_object_event_callback_add
1883       (obj, EVAS_CALLBACK_KEY_DOWN, _on_layout_key_down, NULL);
1884
1885    priv->box = elm_box_add(obj);
1886    str = elm_layout_data_get(obj, "horizontal_pad");
1887    if (str) hpad = atoi(str);
1888    str = elm_layout_data_get(obj, "vertical_pad");
1889    if (str) vpad = atoi(str);
1890    elm_box_padding_set
1891       (priv->box,
1892        hpad * elm_widget_scale_get(obj) * elm_config_scale_get(),
1893        vpad * elm_widget_scale_get(obj) * elm_config_scale_get());
1894    elm_box_layout_set(priv->box, _box_layout, obj, NULL);
1895    elm_layout_content_set(obj, "box.swallow", priv->box);
1896    evas_object_event_callback_add
1897       (priv->box, EVAS_CALLBACK_RESIZE, _on_box_resize, obj);
1898
1899    priv->entry = elm_entry_add(obj);
1900    elm_entry_single_line_set(priv->entry, EINA_TRUE);
1901    elm_entry_scrollable_set(priv->entry, EINA_TRUE);
1902    elm_entry_cnp_mode_set(priv->entry, ELM_CNP_MODE_PLAINTEXT);
1903    evas_object_size_hint_weight_set
1904       (priv->entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1905    evas_object_size_hint_align_set
1906       (priv->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1907    evas_object_event_callback_add
1908       (priv->entry, EVAS_CALLBACK_KEY_DOWN, _on_entry_key_down, obj);
1909    evas_object_smart_callback_add
1910       (priv->entry, "unfocused", _on_entry_unfocused, obj);
1911    elm_entry_markup_filter_append(priv->entry, _entry_filter, obj);
1912    elm_box_pack_end(priv->box, priv->entry);
1913    evas_object_show(priv->entry);
1914
1915    elm_widget_can_focus_set(obj, EINA_TRUE);
1916
1917    priv->editable = EINA_TRUE;
1918    priv->expanded = EINA_TRUE;
1919    priv->expanded_state = EINA_TRUE;
1920
1921 #if 0
1922    // ACCESS
1923    _elm_access_object_register(obj, ELM_WIDGET_DATA(priv)->resize_obj);
1924    _elm_access_text_set
1925       (_elm_access_object_get(obj), ELM_ACCESS_TYPE, E_("multi button entry"));
1926    _elm_access_callback_set
1927       (_elm_access_object_get(obj), ELM_ACCESS_INFO, _access_info_cb, NULL);
1928 #endif
1929 }
1930
1931 static void
1932 _elm_multibuttonentry_smart_del(Evas_Object *obj)
1933 {
1934    Elm_Multibuttonentry_Item *it;
1935    Elm_Multibuttonentry_Item_Filter *ft;
1936
1937    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1938
1939 #ifdef _VI_EFFECT
1940    EINA_LIST_FREE(sd->items, it)
1941      {
1942         Elm_Transit *trans;
1943         Evas_Object *rect;
1944
1945         trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
1946         if (trans)
1947           {
1948              elm_transit_del_cb_set(trans, NULL, NULL);
1949              elm_transit_del(trans);
1950           }
1951
1952         rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
1953         if (rect)
1954           {
1955              Ecore_Animator *anim;
1956              anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
1957              if (anim) ecore_animator_del(anim);
1958
1959              evas_object_del(rect);
1960              evas_object_data_set(VIEW(it), "effect_rect", NULL);
1961           }
1962         elm_widget_item_free(it);
1963      }
1964 #else
1965    EINA_LIST_FREE(sd->items, it)
1966       elm_widget_item_free(it);
1967 #endif
1968
1969    EINA_LIST_FREE(sd->filters, ft)
1970       free(ft);
1971
1972    if (sd->end) evas_object_del(sd->end);
1973    if (sd->guide) evas_object_del(sd->guide);
1974    if (sd->label) evas_object_del(sd->label);
1975    if (sd->entry) evas_object_del(sd->entry);
1976    if (sd->box) evas_object_del(sd->box);
1977    if (sd->longpress_timer) ecore_timer_del(sd->longpress_timer);
1978
1979    ELM_WIDGET_CLASS(_elm_multibuttonentry_parent_sc)->base.del(obj);
1980 }
1981
1982 static void
1983 _elm_multibuttonentry_smart_access(Evas_Object *obj, Eina_Bool is_access)
1984 {
1985    Eina_List *elist = NULL;
1986    Elm_Multibuttonentry_Item *it;
1987
1988    ELM_MULTIBUTTONENTRY_CHECK(obj);
1989    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
1990
1991    EINA_LIST_FOREACH(sd->items, elist, it)
1992      _access_widget_item_register(it, is_access);
1993 }
1994
1995 static void
1996 _elm_multibuttonentry_smart_set_user(Elm_Multibuttonentry_Smart_Class *sc)
1997 {
1998    ELM_WIDGET_CLASS(sc)->base.add = _elm_multibuttonentry_smart_add;
1999    ELM_WIDGET_CLASS(sc)->base.del = _elm_multibuttonentry_smart_del;
2000
2001    ELM_WIDGET_CLASS(sc)->theme = _elm_multibuttonentry_smart_theme;
2002    ELM_WIDGET_CLASS(sc)->on_focus = _elm_multibuttonentry_smart_on_focus;
2003
2004    /* not a 'focus chain manager' */
2005    ELM_WIDGET_CLASS(sc)->focus_next = NULL;
2006    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
2007
2008    ELM_LAYOUT_CLASS(sc)->text_set = _elm_multibuttonentry_smart_text_set;
2009    ELM_LAYOUT_CLASS(sc)->text_get = _elm_multibuttonentry_smart_text_get;
2010
2011    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_multibuttonentry_smart_sizing_eval;
2012
2013    // ACCESS
2014    if (_elm_config->access_mode)
2015       ELM_WIDGET_CLASS(sc)->focus_next = _elm_multibuttonentry_smart_focus_next;
2016
2017    ELM_WIDGET_CLASS(sc)->access = _elm_multibuttonentry_smart_access;
2018 }
2019
2020 EAPI const Elm_Multibuttonentry_Smart_Class *
2021 elm_multibuttonentry_smart_class_get(void)
2022 {
2023    static Elm_Multibuttonentry_Smart_Class _sc =
2024       ELM_MULTIBUTTONENTRY_SMART_CLASS_INIT_NAME_VERSION
2025       (ELM_MULTIBUTTONENTRY_SMART_NAME);
2026    static const Elm_Multibuttonentry_Smart_Class *class = NULL;
2027    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
2028
2029    if (class) return class;
2030
2031    _elm_multibuttonentry_smart_set(&_sc);
2032    esc->callbacks = _smart_callbacks;
2033    class = &_sc;
2034
2035    return class;
2036 }
2037
2038 EAPI Evas_Object *
2039 elm_multibuttonentry_add(Evas_Object *parent)
2040 {
2041    Evas_Object *obj;
2042
2043    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2044
2045    obj = elm_widget_add(_elm_multibuttonentry_smart_class_new(), parent);
2046    if (!obj) return NULL;
2047
2048    if (!elm_widget_sub_object_add(parent, obj))
2049      ERR("could not add %p as sub object of %p", obj, parent);
2050
2051    return obj;
2052 }
2053
2054 EAPI Evas_Object *
2055 elm_multibuttonentry_entry_get(const Evas_Object *obj)
2056 {
2057    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2058    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2059
2060    return sd->entry;
2061 }
2062
2063 EAPI void
2064 elm_multibuttonentry_expanded_set(Evas_Object *obj,
2065                                   Eina_Bool expanded)
2066 {
2067    ELM_MULTIBUTTONENTRY_CHECK(obj);
2068    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2069
2070    expanded = !!expanded;
2071    if (sd->expanded == expanded) return;
2072    sd->expanded = expanded;
2073
2074    if (elm_object_focus_get(obj)) return;
2075
2076    if (sd->expanded)
2077      _layout_expand(obj);
2078    else
2079      _layout_shrink(obj, EINA_FALSE);
2080 }
2081
2082 EAPI Eina_Bool
2083 elm_multibuttonentry_expanded_get(const Evas_Object *obj)
2084 {
2085    ELM_MULTIBUTTONENTRY_CHECK(obj) EINA_FALSE;
2086    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2087
2088    return (elm_object_focus_get(obj) || sd->expanded);
2089 }
2090
2091 EAPI void
2092 elm_multibuttonentry_editable_set(Evas_Object *obj,
2093                                   Eina_Bool editable)
2094 {
2095    ELM_MULTIBUTTONENTRY_CHECK(obj);
2096    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2097
2098    editable = !!editable;
2099    if (sd->editable == editable) return;
2100    sd->editable = editable;
2101
2102    if (sd->editable)
2103      {
2104         if (!(sd->guide && _guide_packed(obj)))
2105           {
2106              elm_box_pack_end(sd->box, sd->entry);
2107              evas_object_show(sd->entry);
2108           }
2109
2110         if (!elm_object_focus_get(obj))
2111           elm_layout_signal_emit(obj, "elm,state,event,block", "");
2112      }
2113    else
2114      {
2115         if (!(sd->guide && _guide_packed(obj)))
2116           {
2117              elm_box_unpack(sd->box, sd->entry);
2118              evas_object_hide(sd->entry);
2119           }
2120
2121         if (!elm_object_focus_get(obj))
2122           elm_layout_signal_emit(obj, "elm,state,event,allow", "");
2123      }
2124 }
2125
2126 EAPI Eina_Bool
2127 elm_multibuttonentry_editable_get(const Evas_Object *obj)
2128 {
2129    ELM_MULTIBUTTONENTRY_CHECK(obj) EINA_FALSE;
2130    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2131
2132    return sd->editable;
2133 }
2134
2135 EAPI Elm_Object_Item *
2136 elm_multibuttonentry_item_prepend(Evas_Object *obj,
2137                                   const char *label,
2138                                   Evas_Smart_Cb func,
2139                                   const void *data)
2140 {
2141    Elm_Multibuttonentry_Item *it;
2142
2143    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2144    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2145
2146    if (!label) return NULL;
2147
2148    // if guide text was shown, hide it
2149    if (sd->guide && _guide_packed(obj))
2150      {
2151         elm_box_unpack(sd->box, sd->guide);
2152         evas_object_hide(sd->guide);
2153
2154         if (sd->editable)
2155           {
2156              elm_box_pack_end(sd->box, sd->entry);
2157              evas_object_show(sd->entry);
2158           }
2159      }
2160
2161    it = _item_new(obj, label, func, data);
2162    if (!it) return NULL;
2163
2164    sd->items = eina_list_prepend(sd->items, it);
2165
2166    if (!elm_object_focus_get(obj) && !sd->expanded && sd->boxw)
2167      {
2168 #ifdef _VI_EFFECT
2169         _item_adding_effect_add(obj, it);
2170 #endif
2171         _layout_shrink(obj, EINA_TRUE);
2172      }
2173    else
2174      {
2175 #ifdef _VI_EFFECT
2176         if (sd->boxh && sd->boxw)
2177           _item_adding_effect_add(obj, it);
2178         else
2179           {
2180              if (sd->label && _label_packed(obj))
2181                elm_box_pack_after(sd->box, VIEW(it), sd->label);
2182              else
2183                elm_box_pack_start(sd->box, VIEW(it));
2184              evas_object_show(VIEW(it));
2185           }
2186 #else
2187         if (sd->label && _label_packed(obj))
2188           elm_box_pack_after(sd->box, VIEW(it), sd->label);
2189         else
2190           elm_box_pack_start(sd->box, VIEW(it));
2191         evas_object_show(VIEW(it));
2192 #endif
2193      }
2194
2195 #ifdef _VI_EFFECT
2196    if (!sd->boxh || !sd->boxw)
2197      evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2198 #else
2199    evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2200 #endif
2201
2202    return (Elm_Object_Item *)it;
2203 }
2204
2205 EAPI Elm_Object_Item *
2206 elm_multibuttonentry_item_append(Evas_Object *obj,
2207                                  const char *label,
2208                                  Evas_Smart_Cb func,
2209                                  const void *data)
2210 {
2211    Elm_Multibuttonentry_Item *it;
2212
2213    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2214    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2215
2216    if (!label) return NULL;
2217
2218    // if guide text was shown, hide it
2219    if (sd->guide && _guide_packed(obj))
2220      {
2221         elm_box_unpack(sd->box, sd->guide);
2222         evas_object_hide(sd->guide);
2223
2224         if (sd->editable)
2225           {
2226              elm_box_pack_end(sd->box, sd->entry);
2227              evas_object_show(sd->entry);
2228           }
2229      }
2230
2231    it = _item_new(obj, label, func, data);
2232    if (!it) return NULL;
2233
2234    sd->items = eina_list_append(sd->items, it);
2235
2236    if (!elm_object_focus_get(obj) && !sd->expanded && sd->boxw)
2237      {
2238 #ifdef _VI_EFFECT
2239         _item_adding_effect_add(obj, it);
2240 #endif
2241         _layout_shrink(obj, EINA_TRUE);
2242      }
2243    else
2244      {
2245 #ifdef _VI_EFFECT
2246         if (sd->boxh && sd->boxw)
2247           _item_adding_effect_add(obj, it);
2248         else
2249           {
2250              if (sd->editable)
2251                elm_box_pack_before(sd->box, VIEW(it), sd->entry);
2252              else
2253                elm_box_pack_end(sd->box, VIEW(it));
2254              evas_object_show(VIEW(it));
2255           }
2256 #else
2257         if (sd->editable)
2258           elm_box_pack_before(sd->box, VIEW(it), sd->entry);
2259         else
2260           elm_box_pack_end(sd->box, VIEW(it));
2261         evas_object_show(VIEW(it));
2262 #endif
2263      }
2264
2265 #ifdef _VI_EFFECT
2266    if (!sd->boxh || !sd->boxw)
2267      evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2268 #else
2269    evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2270 #endif
2271
2272    return (Elm_Object_Item *)it;
2273 }
2274
2275 EAPI Elm_Object_Item *
2276 elm_multibuttonentry_item_insert_before(Evas_Object *obj,
2277                                         Elm_Object_Item *before,
2278                                         const char *label,
2279                                         Evas_Smart_Cb func,
2280                                         const void *data)
2281 {
2282    Elm_Multibuttonentry_Item *it;
2283
2284    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2285    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2286
2287    if (!label) return NULL;
2288    if (!before) return NULL;
2289
2290    it = _item_new(obj, label, func, data);
2291    if (!it) return NULL;
2292
2293    sd->items = eina_list_prepend_relative(sd->items, it, before);
2294
2295    if (!elm_object_focus_get(obj) && !sd->expanded && sd->boxw)
2296      {
2297 #ifdef _VI_EFFECT
2298         _item_adding_effect_add(obj, it);
2299 #endif
2300         _layout_shrink(obj, EINA_TRUE);
2301      }
2302    else
2303      {
2304 #ifdef _VI_EFFECT
2305         if (sd->boxh && sd->boxw)
2306           _item_adding_effect_add(obj, it);
2307         else
2308           {
2309              elm_box_pack_before(sd->box, VIEW(it), VIEW(before));
2310              evas_object_show(VIEW(it));
2311           }
2312 #else
2313         elm_box_pack_before(sd->box, VIEW(it), VIEW(before));
2314         evas_object_show(VIEW(it));
2315 #endif
2316      }
2317
2318 #ifdef _VI_EFFECT
2319    if (!sd->boxh || !sd->boxw)
2320      evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2321 #else
2322    evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2323 #endif
2324
2325    return (Elm_Object_Item *)it;
2326 }
2327
2328 EAPI Elm_Object_Item *
2329 elm_multibuttonentry_item_insert_after(Evas_Object *obj,
2330                                        Elm_Object_Item *after,
2331                                        const char *label,
2332                                        Evas_Smart_Cb func,
2333                                        const void *data)
2334 {
2335    Elm_Multibuttonentry_Item *it;
2336
2337    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2338    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2339
2340    if (!label) return NULL;
2341    if (!after) return NULL;
2342
2343    it = _item_new(obj, label, func, data);
2344    if (!it) return NULL;
2345
2346    sd->items = eina_list_append_relative(sd->items, it, after);
2347
2348    if (!elm_object_focus_get(obj) && !sd->expanded && sd->boxw)
2349      {
2350 #ifdef _VI_EFFECT
2351         _item_adding_effect_add(obj, it);
2352 #endif
2353         _layout_shrink(obj, EINA_TRUE);
2354      }
2355    else
2356      {
2357 #ifdef _VI_EFFECT
2358         if (sd->boxw && sd->boxh)
2359           _item_adding_effect_add(obj, it);
2360         else
2361           {
2362              elm_box_pack_after(sd->box, VIEW(it), VIEW(after));
2363              evas_object_show(VIEW(it));
2364           }
2365 #else
2366         elm_box_pack_after(sd->box, VIEW(it), VIEW(after));
2367         evas_object_show(VIEW(it));
2368 #endif
2369      }
2370
2371 #ifdef _VI_EFFECT
2372    if (!sd->boxh || !sd->boxw)
2373      evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2374 #else
2375    evas_object_smart_callback_call(obj, SIG_ITEM_ADDED, it);
2376 #endif
2377
2378    return (Elm_Object_Item *)it;
2379 }
2380
2381 EAPI const Eina_List *
2382 elm_multibuttonentry_items_get(const Evas_Object *obj)
2383 {
2384    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2385    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2386
2387    return sd->items;
2388 }
2389
2390 EAPI Evas_Object *
2391 elm_multibuttonentry_item_object_get(const Elm_Object_Item *it)
2392 {
2393    ELM_MULTIBUTTONENTRY_ITEM_CHECK_OR_RETURN(it, NULL);
2394
2395    return VIEW(it);
2396 }
2397
2398 EAPI Elm_Object_Item *
2399 elm_multibuttonentry_first_item_get(const Evas_Object *obj)
2400 {
2401    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2402    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2403
2404    return eina_list_data_get(sd->items);
2405 }
2406
2407 EAPI Elm_Object_Item *
2408 elm_multibuttonentry_last_item_get(const Evas_Object *obj)
2409 {
2410    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2411    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2412
2413    return eina_list_data_get(eina_list_last(sd->items));
2414 }
2415
2416 EAPI Elm_Object_Item *
2417 elm_multibuttonentry_selected_item_get(const Evas_Object *obj)
2418 {
2419    ELM_MULTIBUTTONENTRY_CHECK(obj) NULL;
2420    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2421
2422    return sd->selected_item;
2423 }
2424
2425 EAPI void
2426 elm_multibuttonentry_item_selected_set(Elm_Object_Item *it,
2427                                        Eina_Bool selected)
2428 {
2429    ELM_MULTIBUTTONENTRY_ITEM_CHECK_OR_RETURN(it);
2430    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
2431
2432    if (!elm_object_focus_get(WIDGET(it))) return;
2433
2434    if (selected && it != sd->selected_item)
2435      {
2436         evas_object_focus_set(elm_layout_edje_get(VIEW(it)), EINA_TRUE);
2437      }
2438    else if (!selected && it == sd->selected_item)
2439      {
2440         evas_object_focus_set(elm_layout_edje_get(VIEW(it)), EINA_FALSE);
2441
2442         if (sd->editable)
2443           elm_object_focus_set(sd->entry, EINA_TRUE);
2444      }
2445 }
2446
2447 EAPI Eina_Bool
2448 elm_multibuttonentry_item_selected_get(const Elm_Object_Item *it)
2449 {
2450    ELM_MULTIBUTTONENTRY_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
2451    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
2452
2453    if (!elm_object_focus_get(WIDGET(it))) return EINA_FALSE;
2454
2455    if (it == sd->selected_item)
2456      return EINA_TRUE;
2457
2458    return EINA_FALSE;
2459 }
2460
2461 EAPI void
2462 elm_multibuttonentry_clear(Evas_Object *obj)
2463 {
2464    Elm_Multibuttonentry_Item *it;
2465
2466    ELM_MULTIBUTTONENTRY_CHECK(obj);
2467    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2468
2469 #ifdef _VI_EFFECT
2470    EINA_LIST_FREE(sd->items, it)
2471      {
2472         Elm_Transit *trans;
2473         Evas_Object *rect;
2474
2475         trans = (Elm_Transit *)evas_object_data_get(VIEW(it), "transit");
2476         if (trans)
2477           {
2478              elm_transit_del_cb_set(trans, NULL, NULL);
2479              elm_transit_del(trans);
2480           }
2481
2482         rect = (Evas_Object *)evas_object_data_get(VIEW(it), "effect_rect");
2483         if (rect)
2484           {
2485              Ecore_Animator *anim;
2486
2487              anim = (Ecore_Animator*)evas_object_data_get(rect, "animator");
2488              if (anim) ecore_animator_del(anim);
2489
2490              evas_object_del(rect);
2491              evas_object_data_set(VIEW(it), "effect_rect", NULL);
2492
2493              if (sd->editable)
2494                {
2495                   elm_box_pack_end(sd->box, sd->entry);
2496                   evas_object_show(sd->entry);
2497                   if (elm_object_focus_get(WIDGET(it)))
2498                     elm_object_focus_set(sd->entry, EINA_TRUE);
2499                }
2500           }
2501         elm_widget_item_free(it);
2502      }
2503 #else
2504    EINA_LIST_FREE(sd->items, it)
2505       elm_widget_item_free(it);
2506 #endif
2507
2508    sd->items = NULL;
2509    sd->item_be_selected = EINA_FALSE;
2510    sd->expanded_state = EINA_TRUE;
2511
2512    if (sd->end)
2513      {
2514         evas_object_del(sd->end);
2515         sd->end = NULL;
2516      }
2517
2518    if (!sd->items && !elm_object_focus_get(obj) &&
2519        sd->guide && !_guide_packed(obj))
2520      {
2521         if (sd->editable)
2522           {
2523              elm_box_unpack(sd->box, sd->entry);
2524              evas_object_hide(sd->entry);
2525           }
2526
2527         elm_box_pack_end(sd->box, sd->guide);
2528         evas_object_show(sd->guide);
2529      }
2530 }
2531
2532 EAPI Elm_Object_Item *
2533 elm_multibuttonentry_item_prev_get(const Elm_Object_Item *it)
2534 {
2535    Eina_List *l;
2536    Elm_Multibuttonentry_Item *item;
2537
2538    ELM_MULTIBUTTONENTRY_ITEM_CHECK_OR_RETURN(it, NULL);
2539    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
2540
2541    EINA_LIST_FOREACH(sd->items, l, item)
2542      {
2543         if (item == (Elm_Multibuttonentry_Item *)it)
2544           {
2545              l = eina_list_prev(l);
2546              if (!l) return NULL;
2547              return eina_list_data_get(l);
2548           }
2549      }
2550    return NULL;
2551 }
2552
2553 EAPI Elm_Object_Item *
2554 elm_multibuttonentry_item_next_get(const Elm_Object_Item *it)
2555 {
2556    Eina_List *l;
2557    Elm_Multibuttonentry_Item *item;
2558
2559    ELM_MULTIBUTTONENTRY_ITEM_CHECK_OR_RETURN(it, NULL);
2560    ELM_MULTIBUTTONENTRY_DATA_GET(WIDGET(it), sd);
2561
2562    EINA_LIST_FOREACH(sd->items, l, item)
2563      {
2564         if (item == (Elm_Multibuttonentry_Item *)it)
2565           {
2566              l = eina_list_next(l);
2567              if (!l) return NULL;
2568              return eina_list_data_get(l);
2569           }
2570      }
2571    return NULL;
2572 }
2573
2574 EAPI void
2575 elm_multibuttonentry_item_filter_append(Evas_Object *obj,
2576                                         Elm_Multibuttonentry_Item_Filter_Cb func,
2577                                         const void *data)
2578 {
2579    Elm_Multibuttonentry_Item_Filter *ft = NULL;
2580
2581    ELM_MULTIBUTTONENTRY_CHECK(obj);
2582    EINA_SAFETY_ON_NULL_RETURN(func);
2583    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2584
2585    ft = _filter_new(func, data);
2586    if (!ft) return;
2587
2588    sd->filters = eina_list_append(sd->filters, ft);
2589 }
2590
2591 EAPI void
2592 elm_multibuttonentry_item_filter_prepend(Evas_Object *obj,
2593                                          Elm_Multibuttonentry_Item_Filter_Cb func,
2594                                          const void *data)
2595 {
2596    Elm_Multibuttonentry_Item_Filter *ft = NULL;
2597
2598    ELM_MULTIBUTTONENTRY_CHECK(obj);
2599    EINA_SAFETY_ON_NULL_RETURN(func);
2600    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2601
2602    ft = _filter_new(func, data);
2603    if (!ft) return;
2604
2605    sd->filters = eina_list_prepend(sd->filters, ft);
2606 }
2607
2608 EAPI void
2609 elm_multibuttonentry_item_filter_remove(Evas_Object *obj,
2610                                         Elm_Multibuttonentry_Item_Filter_Cb func,
2611                                         const void *data)
2612 {
2613    Elm_Multibuttonentry_Item_Filter *ft;
2614    Eina_List *l;
2615
2616    ELM_MULTIBUTTONENTRY_CHECK(obj);
2617    EINA_SAFETY_ON_NULL_RETURN(func);
2618    ELM_MULTIBUTTONENTRY_DATA_GET(obj, sd);
2619
2620    EINA_LIST_FOREACH(sd->filters, l, ft)
2621      {
2622         if ((ft->func == func) && (!data || ft->data == data))
2623           {
2624              sd->filters = eina_list_remove_list(sd->filters, l);
2625              free(ft);
2626              return;
2627           }
2628      }
2629 }