Merge "[multibuttonentry]CQ:H0100137536- 'item,selected' signal sends 2 times when...
[framework/uifw/elementary.git] / src / lib / elc_multibuttonentry.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define MAX_STR 256
5 #define MIN_W_ENTRY 20
6
7 typedef enum _Multibuttonentry_Pos
8   {
9      MULTIBUTTONENTRY_POS_START,
10      MULTIBUTTONENTRY_POS_END,
11      MULTIBUTTONENTRY_POS_BEFORE,
12      MULTIBUTTONENTRY_POS_AFTER,
13      MULTIBUTTONENTRY_POS_NUM
14   } Multibuttonentry_Pos;
15
16 typedef enum _Multibuttonentry_Button_State
17   {
18      MULTIBUTTONENTRY_BUTTON_STATE_DEFAULT,
19      MULTIBUTTONENTRY_BUTTON_STATE_SELECTED,
20      MULTIBUTTONENTRY_BUTTON_STATE_NUM
21   } Multibuttonentry_Button_State;
22
23 typedef enum _MultiButtonEntry_Closed_Button_Type
24   {
25      MULTIBUTTONENTRY_CLOSED_IMAGE,
26      MULTIBUTTONENTRY_CLOSED_LABEL
27   } MultiButtonEntry_Closed_Button_Type;
28
29 typedef enum _Multibuttonentry_View_State
30   {
31      MULTIBUTTONENTRY_VIEW_NONE,
32      MULTIBUTTONENTRY_VIEW_GUIDETEXT,
33      MULTIBUTTONENTRY_VIEW_ENTRY,
34      MULTIBUTTONENTRY_VIEW_CONTRACTED
35   } Multibuttonentry_View_State;
36
37 struct _Multibuttonentry_Item
38   {
39      Evas_Object *multibuttonentry;
40      Evas_Object *button;
41      void *data;
42      Evas_Coord vw, rw; // vw: visual width, real width
43      Eina_Bool  visible: 1;
44   };
45
46 typedef struct _Widget_Data Widget_Data;
47 struct _Widget_Data
48   {
49      Evas_Object *base;
50      Evas_Object *box;
51      Evas_Object *entry;
52      Evas_Object *label;
53      Evas_Object *guidetext;
54      Evas_Object *end;   // used to represent the total number of invisible buttons
55
56      Evas_Object *rect_for_end;
57      MultiButtonEntry_Closed_Button_Type end_type;
58
59      Eina_List *items;
60      Eina_List *current;
61
62      int n_str;
63      Multibuttonentry_View_State view_state;
64
65      Evas_Coord w_box, h_box;
66      int  contracted;
67      Eina_Bool focused: 1;
68      Eina_Bool last_btn_select: 1;
69      Elm_Multibuttonentry_Item_Verify_Callback add_callback;
70      void *add_callback_data;
71   };
72
73 static const char *widtype = NULL;
74 static void _del_hook(Evas_Object *obj);
75 static void _theme_hook(Evas_Object *obj);
76 static void _on_focus_hook(void *data __UNUSED__, Evas_Object *obj);
77 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src, Evas_Callback_Type type, void *event_info);
78 static void _sizing_eval(Evas_Object *obj);
79 static void _changed_size_hint_cb(void *data, Evas *evas, Evas_Object *obj, void *event);
80 static void _resize_cb(void *data, Evas *evas, Evas_Object *obj, void *event);
81 static void _event_init(Evas_Object *obj);
82 static void _contracted_state_set(Evas_Object *obj, int contracted);
83 static void _view_update(Evas_Object *obj);
84 static void _set_label(Evas_Object *obj, const char *str);
85 static void _change_current_button_state(Evas_Object *obj, Multibuttonentry_Button_State state);
86 static void _change_current_button(Evas_Object *obj, Evas_Object *btn);
87 static void _button_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
88 static void _del_button_obj(Evas_Object *obj, Evas_Object *btn);
89 static void _del_button_item(Elm_Multibuttonentry_Item *item);
90 static void _select_button(Evas_Object *obj, Evas_Object *btn);
91 static Elm_Multibuttonentry_Item *_add_button_item(Evas_Object *obj, const char *str, Multibuttonentry_Pos pos,
92                                                    const Elm_Multibuttonentry_Item *reference, void *data);
93 static void _add_button(Evas_Object *obj, char *str);
94 static void _evas_mbe_key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
95 static void _entry_changed_cb(void *data, Evas_Object *obj, void *event_info);
96 static void _entry_key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
97 static void _entry_key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
98 static void _entry_resized_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
99 static void _entry_focus_in_cb(void *data, Evas_Object *obj, void *event_info);
100 static void _entry_focus_out_cb(void *data, Evas_Object *obj, void *event_info);
101 static void _entry_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__);
102 static void _view_init(Evas_Object *obj);
103 static void _set_vis_guidetext(Evas_Object *obj);
104 static void _calculate_box_min_size(Evas_Object *box, Evas_Object_Box_Data *priv);
105 static Evas_Coord _calculate_item_max_height(Evas_Object *box, Evas_Object_Box_Data *priv, int obj_index);
106 static void _box_layout_cb(Evas_Object *o, Evas_Object_Box_Data *priv, void *data);
107
108 static void
109 _del_hook(Evas_Object *obj)
110 {
111    Widget_Data *wd = elm_widget_data_get(obj);
112
113    if (!wd) return;
114    if (wd->items)
115      {
116         Elm_Multibuttonentry_Item *item;
117         EINA_LIST_FREE(wd->items, item)
118           {
119              _del_button_obj(obj, item->button);
120              free(item);
121           }
122         wd->items = NULL;
123      }
124    wd->current = NULL;
125
126    if (wd->entry) evas_object_del (wd->entry);
127    if (wd->label) evas_object_del (wd->label);
128    if (wd->guidetext) evas_object_del (wd->guidetext);
129    if (wd->end) evas_object_del (wd->end);
130    if (wd->rect_for_end) evas_object_del(wd->rect_for_end);
131 }
132
133 static void
134 _theme_hook(Evas_Object *obj)
135 {
136    Widget_Data *wd = elm_widget_data_get(obj);
137    Eina_List *l;
138    Elm_Multibuttonentry_Item *item;
139
140    if (!wd) return;
141
142    _elm_theme_object_set(obj, wd->base, "multibuttonentry", "base", elm_widget_style_get(obj));
143    if (wd->box) edje_object_part_swallow (wd->base, "box.swallow", wd->box);
144    edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
145
146    EINA_LIST_FOREACH(wd->items, l, item)
147      {
148         if (item->button)
149           _elm_theme_object_set(obj, item->button, "multibuttonentry", "btn", elm_widget_style_get (obj));
150         edje_object_scale_set(item->button, elm_widget_scale_get(obj) * _elm_config->scale);
151      }
152
153    _sizing_eval(obj);
154 }
155
156 static void
157 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
158 {
159    Widget_Data *wd = elm_widget_data_get(obj);
160
161    if (!wd) return;
162
163    Ecore_IMF_Context *imf_context = elm_entry_imf_context_get(wd->entry);
164
165    if (elm_widget_focus_get(obj))
166      {
167         if ((imf_context) && (wd->current))
168           {
169              ecore_imf_context_input_panel_show(imf_context);
170           }
171         else if ((imf_context) && ((!wd->current) || (!eina_list_count(wd->items))))
172           {
173              _view_update(obj);
174              ecore_imf_context_input_panel_show(imf_context);
175           }
176         wd->focused = EINA_TRUE;
177         evas_object_smart_callback_call(obj, "focused", NULL);
178      }
179    else
180      {
181         wd->focused = EINA_FALSE;
182         _view_update(obj);
183         if (imf_context) ecore_imf_context_input_panel_hide(imf_context);
184         evas_object_smart_callback_call(obj, "unfocused", NULL);
185      }
186 }
187
188 static Eina_Bool
189 _event_hook(Evas_Object *obj __UNUSED__, Evas_Object *src __UNUSED__, Evas_Callback_Type type __UNUSED__, void *event_info __UNUSED__)
190 {
191    return EINA_TRUE;
192 }
193
194 static void
195 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
196 {
197    Widget_Data *wd = elm_widget_data_get(obj);
198
199    if (!wd) return;
200    edje_object_signal_emit(wd->base, emission, source);
201 }
202
203 static void
204 _sizing_eval(Evas_Object *obj)
205 {
206    Widget_Data *wd = elm_widget_data_get(obj);
207    Evas_Coord minw = -1, minh = -1;
208    Evas_Coord left, right, top, bottom;
209
210    if (!wd) return;
211    evas_object_size_hint_min_get(wd->box, &minw, &minh);
212    edje_object_part_geometry_get(wd->base, "top.left.pad", NULL, NULL, &left, &top);
213    edje_object_part_geometry_get(wd->base, "bottom.right.pad", NULL, NULL, &right, &bottom);
214
215    minw += (left + right);
216    minh += (top + bottom);
217
218    evas_object_size_hint_min_set(obj, minw, minh);
219 }
220
221 static void
222 _signal_mouse_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
223 {
224    Widget_Data *wd = elm_widget_data_get(data);
225
226    if (!wd || !wd->base) return;
227    wd->focused = EINA_TRUE;
228    _view_update(data);
229
230    Ecore_IMF_Context *imf_context = elm_entry_imf_context_get(wd->entry);
231
232    if (imf_context) ecore_imf_context_input_panel_show(imf_context);
233    evas_object_smart_callback_call(data, "clicked", NULL);
234 }
235
236 static void
237 _changed_size_hint_cb(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
238 {
239    Evas_Object *eo = (Evas_Object *)data;
240    Widget_Data *wd = elm_widget_data_get(data);
241
242    if (!wd) return;
243    _sizing_eval(eo);
244 }
245
246 static void
247 _resize_cb(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
248 {
249    Widget_Data *wd = elm_widget_data_get(data);
250    Evas_Coord w, h;
251
252    if (!wd) return;
253    evas_object_geometry_get(wd->box, NULL, NULL, &w, &h);
254
255    if (wd->h_box < h) evas_object_smart_callback_call (data, "expanded", NULL);
256    else if (wd->h_box > h) evas_object_smart_callback_call (data, "contracted", NULL);
257
258    wd->w_box = w;
259    wd->h_box = h;
260
261    _view_update(data);
262 }
263
264 static void
265 _event_init(Evas_Object *obj)
266 {
267    Widget_Data *wd = elm_widget_data_get(obj);
268
269    if (!wd || !wd->base) return;
270    if (wd->base)
271      {
272         edje_object_signal_callback_add(wd->base, "mouse,clicked,1", "*", _signal_mouse_clicked, obj);
273         evas_object_event_callback_add(wd->base, EVAS_CALLBACK_KEY_UP, _evas_mbe_key_up_cb, obj);
274      }
275
276    if (wd->box)
277      {
278         evas_object_event_callback_add(wd->box, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
279         evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hint_cb, obj);
280      }
281
282    if (wd->entry)
283      {
284         evas_object_event_callback_add(wd->entry, EVAS_CALLBACK_KEY_UP, _entry_key_up_cb, obj);
285         evas_object_event_callback_add(wd->entry, EVAS_CALLBACK_KEY_DOWN, _entry_key_down_cb, obj);
286         evas_object_event_callback_add(wd->entry, EVAS_CALLBACK_RESIZE, _entry_resized_cb, obj);
287         evas_object_smart_callback_add(wd->entry, "changed", _entry_changed_cb, obj);
288         evas_object_smart_callback_add(wd->entry, "focused", _entry_focus_in_cb, obj);
289         evas_object_smart_callback_add(wd->entry, "unfocused", _entry_focus_out_cb, obj);
290         evas_object_smart_callback_add(wd->entry, "clicked", _entry_clicked_cb, obj);
291      }
292 }
293
294 static void
295 _set_vis_guidetext(Evas_Object *obj)
296 {
297    Widget_Data *wd = elm_widget_data_get(obj);
298
299    if (!wd) return;
300    elm_box_unpack(wd->box, wd->guidetext);
301    elm_box_unpack(wd->box, wd->entry);
302    if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED) return;
303
304    if (wd && (!eina_list_count(wd->items)) && wd->guidetext
305        && (!elm_widget_focus_get(obj)) && (!wd->focused) && (!wd->n_str))
306      {
307         evas_object_hide(wd->entry);
308         elm_box_pack_end(wd->box, wd->guidetext);
309         evas_object_show(wd->guidetext);
310         wd->view_state = MULTIBUTTONENTRY_VIEW_GUIDETEXT;
311      }
312    else
313      {
314         evas_object_hide(wd->guidetext);
315         elm_box_pack_end(wd->box, wd->entry);
316         evas_object_show(wd->entry);
317         if (elm_widget_focus_get(obj) || wd->focused)
318           if (!wd->current)
319             elm_object_focus_set(wd->entry, EINA_TRUE);
320         wd->view_state = MULTIBUTTONENTRY_VIEW_ENTRY;
321      }
322 }
323
324 static void
325 _contracted_state_set(Evas_Object *obj, int contracted)
326 {
327    Widget_Data *wd = elm_widget_data_get(obj);
328    Eina_List *l;
329    Elm_Multibuttonentry_Item *item;
330
331    if (!wd || !wd->box) return;
332    if (wd->view_state == MULTIBUTTONENTRY_VIEW_ENTRY)
333      evas_object_hide(wd->entry);
334    else if (wd->view_state == MULTIBUTTONENTRY_VIEW_GUIDETEXT)
335      evas_object_hide(wd->guidetext);
336    else if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
337      {
338         evas_object_hide(wd->rect_for_end);
339         evas_object_hide(wd->end);
340         wd->view_state = MULTIBUTTONENTRY_VIEW_NONE;
341      }
342
343    if (contracted == 1)
344      {
345         Evas_Coord w=0, w_tmp=0;
346         Evas_Coord box_inner_item_width_padding = 0;
347
348         elm_box_padding_get(wd->box, &box_inner_item_width_padding, NULL);
349         // unpack all items and entry
350         elm_box_unpack_all(wd->box);
351         EINA_LIST_FOREACH(wd->items, l, item)
352           {
353              if (item)
354                {
355                   evas_object_hide(item->button);
356                   item->visible = EINA_FALSE;
357                }
358           }
359         // pack buttons only 1line
360         w = wd->w_box;
361
362         if (wd->label)
363           {
364              elm_box_pack_end(wd->box, wd->label);
365              evas_object_size_hint_min_get(wd->label, &w_tmp, NULL);
366              w -= w_tmp;
367              w -= box_inner_item_width_padding;
368           }
369
370         item = NULL;
371         int count = eina_list_count(wd->items);
372         Evas_Coord button_min_width = 0;
373         /* Evas_Coord button_min_height = 0; */
374         if (wd->end_type == MULTIBUTTONENTRY_CLOSED_IMAGE)
375           {
376              const char *size_str;
377              size_str = edje_object_data_get(wd->end, "closed_button_width");
378              if (size_str) button_min_width = (Evas_Coord)atoi(size_str);
379              /* it use for later
380              size_str = edje_object_data_get(wd->end, "closed_button_height");
381              if (size_str) button_min_width = (Evas_Coord)atoi(size_str);
382               */
383           }
384
385         EINA_LIST_FOREACH(wd->items, l, item)
386           {
387              if (item)
388                {
389                   int w_label_count = 0;
390                   char buf[MAX_STR];
391
392                   elm_box_pack_end(wd->box, item->button);
393                   evas_object_show(item->button);
394                   item->visible = EINA_TRUE;
395
396                   w -= item->vw;
397                   w -= box_inner_item_width_padding;
398                   count--;
399
400                   if (wd->end_type == MULTIBUTTONENTRY_CLOSED_LABEL)
401                     {
402                        if (count > 0)
403                          {
404                             snprintf(buf, sizeof(buf), "... + %d", count);
405                             elm_object_text_set(wd->end, buf);
406                             evas_object_size_hint_min_get(wd->end, &w_label_count, NULL);
407                          }
408
409                        if (w < 0 || w < w_label_count)
410                          {
411                             elm_box_unpack(wd->box, item->button);
412                             evas_object_hide(item->button);
413                             item->visible = EINA_FALSE;
414
415                             count++;
416                             snprintf(buf, sizeof(buf), "... + %d", count);
417                             elm_object_text_set(wd->end, buf);
418                             evas_object_size_hint_min_get(wd->end, &w_label_count, NULL);
419
420                             elm_box_pack_end(wd->box, wd->end);
421                             evas_object_show(wd->end);
422
423                             wd->view_state = MULTIBUTTONENTRY_VIEW_CONTRACTED;
424                             evas_object_smart_callback_call(obj, "contracted,state,changed", (void *)1);
425                             break;
426                          }
427                     }
428                   else if (wd->end_type == MULTIBUTTONENTRY_CLOSED_IMAGE)
429                     {
430                        if (w < button_min_width)
431                          {
432                             Evas_Coord rectSize;
433                             Evas_Coord closed_height = 0;
434                             const char *height_str = edje_object_data_get(wd->base, "closed_height");
435
436                             if (height_str) closed_height = (Evas_Coord)atoi(height_str);
437                             elm_box_unpack(wd->box, item->button);
438                             evas_object_hide(item->button);
439                             item->visible = EINA_FALSE;
440
441                             w += item->vw;
442                             rectSize = w - button_min_width;
443                             if (!wd->rect_for_end)
444                               {
445                                  Evas *e = evas_object_evas_get(obj);
446                                  wd->rect_for_end = evas_object_rectangle_add(e);
447                                  evas_object_color_set(wd->rect_for_end, 0, 0, 0, 0);
448                               }
449                             evas_object_size_hint_min_set(wd->rect_for_end, rectSize, closed_height * elm_scale_get());
450                             elm_box_pack_end(wd->box, wd->rect_for_end);
451                             evas_object_show(wd->rect_for_end);
452
453                             elm_box_pack_end(wd->box, wd->end);
454                             evas_object_show(wd->end);
455
456                             wd->view_state = MULTIBUTTONENTRY_VIEW_CONTRACTED;
457                             evas_object_smart_callback_call(obj, "contracted,state,changed", (void *)0);
458                             break;
459                          }
460                     }
461                }
462           }
463      }
464    else
465      {
466         // unpack all items and entry
467         elm_box_unpack_all(wd->box);
468         EINA_LIST_FOREACH(wd->items, l, item)
469           {
470              if (item)
471                {
472                   evas_object_hide(item->button);
473                   item->visible = EINA_FALSE;
474                }
475           }
476         evas_object_hide(wd->end);
477
478         if (wd->rect_for_end) evas_object_hide(wd->rect_for_end);
479
480         // pack buttons only 1line
481
482         if (wd->label) elm_box_pack_end(wd->box, wd->label);
483
484         // pack remain btns
485         item = NULL;
486         EINA_LIST_FOREACH(wd->items, l, item)
487           {
488              if (item)
489                {
490                   elm_box_pack_end(wd->box, item->button);
491                   evas_object_show(item->button);
492                   item->visible = EINA_TRUE;
493                }
494           }
495
496         wd->view_state = MULTIBUTTONENTRY_VIEW_NONE;
497         evas_object_smart_callback_call(obj, "contracted,state,changed", (void *)wd->contracted);
498      }
499    if (wd->view_state != MULTIBUTTONENTRY_VIEW_CONTRACTED)
500      {
501         _set_vis_guidetext(obj);
502      }
503 }
504
505 static void
506 _view_update(Evas_Object *obj)
507 {
508    Evas_Coord width = 1, height = 1;
509    Widget_Data *wd = elm_widget_data_get(obj);
510
511    if (!wd || !wd->box || !wd->entry || !(wd->w_box > 0)) return;
512
513    // update label
514    if (wd->label)
515      {
516         elm_box_unpack(wd->box, wd->label);
517         elm_box_pack_start(wd->box, wd->label);
518         evas_object_size_hint_min_get(wd->label, &width, &height);
519      }
520
521    if (wd->guidetext)
522      {
523         Evas_Coord guide_text_width = wd->w_box - width;
524         evas_object_size_hint_min_set(wd->guidetext, guide_text_width, height);
525      }
526
527    // update buttons in contracted mode
528    if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
529      _contracted_state_set(obj, 1);
530
531    // update guidetext
532    _set_vis_guidetext(obj);
533 }
534
535 static void
536 _set_label(Evas_Object *obj, const char* str)
537 {
538    Widget_Data *wd = elm_widget_data_get(obj);
539
540    if (!wd || !str) return;
541    if (wd->label)
542    {
543       Evas_Coord width, height, sum_width = 0;
544       evas_object_size_hint_min_set(wd->label, 0, 0);
545       evas_object_resize(wd->label, 0, 0);
546       edje_object_part_text_set(wd->label, "mbe.label", str);
547
548       if (!strcmp(str, ""))
549         {
550            /* FIXME: not work yet */
551            edje_object_signal_emit(wd->label, "elm,mbe,clear_text", "");
552            edje_object_part_geometry_get(wd->label, "mbe.label", NULL, NULL, &width, &height);
553            sum_width += width;
554         }
555       else
556         {
557            edje_object_signal_emit(wd->label, "elm,mbe,set_text", "");
558            edje_object_part_geometry_get(wd->label, "mbe.label", NULL, NULL, &width, &height);
559
560            sum_width += width;
561
562            edje_object_part_geometry_get(wd->label, "mbe.label.left.padding", NULL, NULL, &width, NULL);
563            sum_width += width;
564
565            edje_object_part_geometry_get(wd->label, "mbe.label.right.padding", NULL, NULL, &width, NULL);
566            sum_width += width;
567         }
568       evas_object_size_hint_min_set(wd->label, sum_width, height);
569    }
570    evas_object_show(wd->label);
571    _view_update(obj);
572 }
573
574 static void
575 _set_guidetext(Evas_Object *obj, const char* str)
576 {
577    Widget_Data *wd = elm_widget_data_get(obj);
578
579    if (!wd || !str) return;
580    if (!wd->guidetext)
581      {
582         if (! (wd->guidetext = edje_object_add (evas_object_evas_get (obj)))) return;
583         _elm_theme_object_set(obj, wd->guidetext, "multibuttonentry", "guidetext", elm_widget_style_get(obj));
584         evas_object_size_hint_weight_set(wd->guidetext, 0.0, EVAS_HINT_EXPAND);
585         evas_object_size_hint_align_set(wd->guidetext, EVAS_HINT_FILL, EVAS_HINT_FILL);
586      }
587
588    if (wd->guidetext) edje_object_part_text_set (wd->guidetext, "elm.text", str);
589    _view_update(obj);
590 }
591
592 static void
593 _change_current_button_state(Evas_Object *obj, Multibuttonentry_Button_State state)
594 {
595    Widget_Data *wd = elm_widget_data_get(obj);
596    Elm_Multibuttonentry_Item *item = NULL;
597
598    if (!wd) return;
599    if (wd->current)
600      item = eina_list_data_get(wd->current);
601
602    if (item && item->button)
603      {
604         switch (state)
605           {
606              case MULTIBUTTONENTRY_BUTTON_STATE_DEFAULT:
607                 edje_object_signal_emit(item->button, "default", "");
608                 wd->current = NULL;
609                 break;
610              case MULTIBUTTONENTRY_BUTTON_STATE_SELECTED:
611                 edje_object_signal_emit(item->button, "focused", "");
612                 evas_object_smart_callback_call(obj, "item,selected", item);
613                 break;
614              default:
615                 edje_object_signal_emit(item->button, "default", "");
616                 wd->current = NULL;
617                 break;
618           }
619      }
620 }
621
622 static void
623 _change_current_button(Evas_Object *obj, Evas_Object *btn)
624 {
625    Widget_Data *wd = elm_widget_data_get(obj);
626    Eina_List *l;
627    Elm_Multibuttonentry_Item *item;
628
629    if (!wd) return;
630
631    // change the state of previous button to "default"
632    _change_current_button_state(obj, MULTIBUTTONENTRY_BUTTON_STATE_DEFAULT);
633
634    // change the current
635    EINA_LIST_FOREACH(wd->items, l, item)
636      {
637         if (item->button == btn)
638           {
639              wd->current = l;
640              break;
641           }
642      }
643    // change the state of current button to "focused"
644    _change_current_button_state(obj, MULTIBUTTONENTRY_BUTTON_STATE_SELECTED);
645 }
646
647 static void
648 _button_clicked(void *data, Evas_Object *obj, const char *emission __UNUSED__, const char *source __UNUSED__)
649 {
650    Widget_Data *wd = elm_widget_data_get(data);
651
652    Elm_Multibuttonentry_Item *item = NULL;
653    if (!wd || wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED) return;
654
655    _select_button(data, obj);
656
657    if ((wd->current) && ((item = eina_list_data_get(wd->current)) != NULL))
658      evas_object_smart_callback_call(data, "item,clicked", item);
659 }
660
661 static void
662 _del_button_obj(Evas_Object *obj, Evas_Object *btn)
663 {
664    Widget_Data *wd = elm_widget_data_get(obj);
665
666    if (!wd || !btn) return;
667    if (btn)
668      evas_object_del(btn);
669 }
670
671 static void
672 _del_button_item(Elm_Multibuttonentry_Item *item)
673 {
674    Eina_List *l;
675    Elm_Multibuttonentry_Item *_item;
676    if (!item) return;
677    Widget_Data *wd;
678
679    Evas_Object *obj = item->multibuttonentry;
680    wd = elm_widget_data_get(obj);
681    if (!wd) return;
682    EINA_LIST_FOREACH(wd->items, l, _item)
683      {
684         if (_item == item)
685           {
686              wd->items = eina_list_remove(wd->items, _item);
687              elm_box_unpack(wd->box, _item->button);
688
689              evas_object_smart_callback_call(obj, "item,deleted", _item);
690
691              _del_button_obj(obj, _item->button);
692
693              free(_item);
694              if (wd->current == l)
695                wd->current = NULL;
696              break;
697           }
698      }
699    if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
700      _contracted_state_set(obj, 1);
701
702    if (!eina_list_count(wd->items))
703      _set_vis_guidetext(obj);
704 }
705
706 static void
707 _select_button(Evas_Object *obj, Evas_Object *btn)
708 {
709    Widget_Data *wd = elm_widget_data_get(obj);
710
711    if (!wd) return;
712    if (btn)
713      {
714         _change_current_button(obj, btn);
715         if (elm_widget_focus_get(obj))
716           {
717              elm_object_focus_set(wd->entry, EINA_FALSE);
718              evas_object_focus_set(btn, EINA_TRUE);
719           }
720      }
721    else
722      {
723         _change_current_button_state(obj, MULTIBUTTONENTRY_BUTTON_STATE_DEFAULT);
724         if (elm_widget_focus_get(obj))
725           elm_object_focus_set(wd->entry, EINA_TRUE);
726      }
727 }
728
729 static void
730 _resize_button(Evas_Object *btn, Evas_Coord *realw, Evas_Coord *vieww)
731 {
732    Evas_Coord rw, vw;
733    Evas_Coord w_text, h_btn, padding_outer, padding_inner;
734    Evas_Coord w_btn = 0, button_max_width = 0;
735    const char *size_str;
736    const char *ellipsis = "<ellipsis=1.0>";
737
738    size_str = edje_object_data_get(btn, "button_max_size");
739    if (size_str) button_max_width = (Evas_Coord)atoi(size_str);
740
741    const char *button_text = edje_object_part_text_get(btn, "elm.btn.text");
742
743    // decide the size of button
744    edje_object_part_geometry_get(btn, "elm.base", NULL, NULL, NULL, &h_btn);
745    edje_object_part_geometry_get(btn, "elm.btn.text", NULL, NULL, &w_text, NULL);
746    edje_object_part_geometry_get(btn, "left.padding", NULL, NULL, &padding_outer, NULL);
747    edje_object_part_geometry_get(btn, "left.inner.padding", NULL, NULL, &padding_inner, NULL);
748    w_btn = w_text + 2*padding_outer + 2*padding_inner;
749
750    rw = w_btn;
751
752    if (button_max_width < w_btn)
753      {
754         vw = button_max_width;
755         edje_object_part_text_set(btn, "elm.btn.text", ellipsis);
756         edje_object_part_text_append(btn, "elm.btn.text", button_text);
757      }
758    else
759      vw = w_btn;
760
761    //resize btn
762    evas_object_resize(btn, vw, h_btn);
763    evas_object_size_hint_min_set(btn, vw, h_btn);
764
765    if (realw) *realw = rw;
766    if (vieww) *vieww = vw;
767 }
768
769 static Elm_Multibuttonentry_Item*
770 _add_button_item(Evas_Object *obj, const char *str, Multibuttonentry_Pos pos, const Elm_Multibuttonentry_Item *reference, void *data)
771 {
772    Elm_Multibuttonentry_Item *item;
773    Evas_Object *btn;
774    Evas_Coord width, height;
775    char *str_utf8 = NULL;
776
777    Widget_Data *wd = elm_widget_data_get(obj);
778
779    if (!wd || !wd->box || !wd->entry) return NULL;
780
781    if ((wd->add_callback) && !wd->add_callback(obj, str, data, wd->add_callback_data)) return NULL;
782
783    //entry is cleared when text is made to button
784    elm_entry_entry_set(wd->entry, "");
785
786    // initialize entry size to be called entry's EVAS_CALLBACK_RESIZE even entry size's doesn't changed
787    evas_object_resize(wd->entry, 0, 0);
788
789    // add button
790    btn = edje_object_add(evas_object_evas_get(obj));
791    str_utf8 = elm_entry_markup_to_utf8(str);
792
793    _elm_theme_object_set(obj, btn, "multibuttonentry", "btn", elm_widget_style_get(obj));
794    edje_object_part_text_set(btn, "elm.btn.text", str_utf8);
795    edje_object_part_geometry_get(btn, "elm.btn.text", NULL, NULL, &width, &height);
796
797    evas_object_size_hint_min_set(btn, width, height);
798
799    edje_object_signal_callback_add(btn, "mouse,clicked,1", "*", _button_clicked, obj);
800    evas_object_size_hint_weight_set(btn, 0.0, 0.0);
801    evas_object_show(btn);
802
803    // append item list
804    item = ELM_NEW(Elm_Multibuttonentry_Item);
805    if (item)
806      {
807         Evas_Coord rw, vw;
808         _resize_button(btn, &rw, &vw);
809         item->multibuttonentry = obj;
810         item->button = btn;
811         item->data = data;
812         item->rw = rw;
813         item->vw = vw;
814         item->visible = EINA_TRUE;
815
816         switch (pos)
817           {
818              case MULTIBUTTONENTRY_POS_START:
819                 wd->items = eina_list_prepend(wd->items, item);
820                 if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
821                   {
822                      elm_widget_sub_object_add(obj, btn);
823                      _contracted_state_set(obj, 1);
824                   }
825                 else
826                   {
827                      if (wd->label)
828                        elm_box_pack_after(wd->box, btn, wd->label);
829                      else
830                        elm_box_pack_start(wd->box, btn);
831                      if (wd->view_state == MULTIBUTTONENTRY_VIEW_GUIDETEXT)
832                        _set_vis_guidetext(obj);
833                   }
834                 break;
835              case MULTIBUTTONENTRY_POS_END:
836                 wd->items = eina_list_append(wd->items, item);
837                 if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
838                   {
839                      elm_widget_sub_object_add(obj, btn);
840                      evas_object_hide(btn);
841                   }
842                 else
843                   {
844                      if (wd->view_state == MULTIBUTTONENTRY_VIEW_GUIDETEXT)
845                        _set_vis_guidetext(obj);
846                      if (wd->entry)
847                        elm_box_pack_before(wd->box, btn, wd->entry);
848                      else
849                        elm_box_pack_end(wd->box, btn);
850                   }
851                 break;
852              case MULTIBUTTONENTRY_POS_BEFORE:
853                 if (reference)
854                      wd->items = eina_list_prepend_relative(wd->items, item, reference);
855                 else
856                      wd->items = eina_list_append(wd->items, item);
857                 if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
858                   {
859                      elm_widget_sub_object_add(obj, btn);
860                      evas_object_hide(btn);
861                      _contracted_state_set(obj, 1);
862                   }
863                 else
864                   {
865                      if (reference)
866                        elm_box_pack_before(wd->box, btn, reference->button);
867                      else
868                        {
869                           if (wd->view_state == MULTIBUTTONENTRY_VIEW_GUIDETEXT)
870                             _set_vis_guidetext(obj);
871                           if (wd->entry)
872                             elm_box_pack_before(wd->box, btn, wd->entry);
873                           else
874                             elm_box_pack_end(wd->box, btn);
875                        }
876                   }
877                 break;
878              case MULTIBUTTONENTRY_POS_AFTER:
879                 if (reference)
880                      wd->items = eina_list_append_relative(wd->items, item, reference);
881                 else
882                      wd->items = eina_list_append(wd->items, item);
883                 if (wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED)
884                   {
885                      elm_widget_sub_object_add(obj, btn);
886                      _contracted_state_set(obj, 1);
887                   }
888                 else
889                   {
890                      if (reference)
891                        elm_box_pack_after(wd->box, btn, reference->button);
892                      else
893                        {
894                           if (wd->view_state == MULTIBUTTONENTRY_VIEW_GUIDETEXT)
895                             _set_vis_guidetext(obj);
896                           if (wd->entry)
897                             elm_box_pack_before(wd->box, btn, wd->entry);
898                           else
899                             elm_box_pack_end(wd->box, btn);
900                        }
901                   }
902                 break;
903              default:
904                 break;
905           }
906      }
907    evas_object_smart_callback_call(obj, "item,added", item);
908
909    free(str_utf8);
910
911    return item;
912 }
913
914 static void
915 _add_button(Evas_Object *obj, char *str)
916 {
917    Widget_Data *wd = elm_widget_data_get(obj);
918    if (!wd) return;
919
920    // add button
921    _add_button_item(obj, str, MULTIBUTTONENTRY_POS_END, NULL, NULL);
922 }
923
924 static void
925 _evas_mbe_key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
926 {
927    Widget_Data *wd = elm_widget_data_get(data);
928    Elm_Multibuttonentry_Item *item = NULL;
929
930    static char str[MAX_STR];
931
932    if (!wd || !wd->base || !wd->box) return;
933
934    strncpy(str, elm_entry_entry_get(wd->entry), MAX_STR);
935    str[MAX_STR - 1] = 0;
936
937    Evas_Event_Key_Up *ev = (Evas_Event_Key_Up*)event_info;
938
939    if (wd->last_btn_select)
940      {
941         if ((wd->current) &&  ( (strcmp (ev->keyname, "BackSpace") == 0) || (strcmp (ev->keyname, "BackSpace (") == 0)))
942           {
943              item = eina_list_data_get(wd->current);
944              if (item)
945                {
946                   _del_button_item(item);
947                   elm_object_focus(wd->entry);
948                }
949           }
950         else if ((((!wd->current) && (wd->n_str == 0) && (strcmp (ev->keyname, "BackSpace") == 0))
951                   || (strcmp (ev->keyname, "BackSpace (") == 0)))
952           {
953              item = eina_list_data_get(eina_list_last(wd->items));
954              if (item)
955                _select_button(data, item->button);
956           }
957      }
958    else
959      wd->last_btn_select = EINA_TRUE;
960 }
961
962 static void
963 _entry_key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
964 {
965    Widget_Data *wd = elm_widget_data_get(data);
966    Evas_Event_Key_Down *ev = (Evas_Event_Key_Down *)event_info;
967
968    if (!wd) return;
969
970    if ((wd->n_str == 1) && (strcmp(ev->keyname, "BackSpace") == 0 || (strcmp(ev->keyname, "BackSpace (") == 0 )))
971      wd->last_btn_select = EINA_FALSE;
972 }
973
974 static void
975 _entry_key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
976 {
977    Widget_Data *wd = elm_widget_data_get(data);
978    Evas_Event_Key_Up *ev = (Evas_Event_Key_Up *) event_info;
979    static char str[MAX_STR];
980
981    if (!wd || !wd->base || !wd->box) return;
982
983    strncpy(str, elm_entry_entry_get(wd->entry), MAX_STR);
984    str[MAX_STR - 1] = 0;
985
986    if ( (strcmp (str, "") != 0) && (strcmp (ev->keyname, "KP_Enter") == 0 || strcmp (ev->keyname, "Return") == 0 ))
987      {
988         _add_button(data, str);
989         wd->n_str = 0;
990         return;
991      }
992 }
993
994 static void
995 _entry_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
996 {
997    Widget_Data *wd = elm_widget_data_get(data);
998    if (!wd) return;
999
1000    _change_current_button_state(data, MULTIBUTTONENTRY_BUTTON_STATE_DEFAULT);
1001    elm_object_focus_set(wd->entry, EINA_TRUE);
1002 }
1003
1004 static void
1005 _entry_focus_in_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1006 {
1007    Widget_Data *wd = elm_widget_data_get(data);
1008    Elm_Multibuttonentry_Item *item = NULL;
1009
1010    if (!wd) return;
1011
1012    if (wd->current)
1013      {
1014         item = eina_list_data_get(wd->current);
1015         elm_object_focus_set(wd->entry, EINA_FALSE);
1016         evas_object_focus_set(item->button, EINA_TRUE);
1017      }
1018 }
1019
1020 static void
1021 _entry_focus_out_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1022 {
1023    Widget_Data *wd = elm_widget_data_get(data);
1024    if (!wd) return;
1025
1026    static char str[MAX_STR];
1027
1028    strncpy(str,elm_entry_entry_get(wd->entry), MAX_STR);
1029    str[MAX_STR -1] = 0;
1030
1031    if (strlen(str))
1032      _add_button(data, str);
1033 }
1034
1035 static void
1036 _entry_changed_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1037 {
1038    Widget_Data *wd = elm_widget_data_get(data);
1039    if (!wd) return;
1040
1041    static char str[MAX_STR];
1042
1043    strncpy(str, elm_entry_entry_get(wd->entry), MAX_STR);
1044    str[MAX_STR -1] = 0;
1045
1046    wd->n_str =  strlen(str);
1047 }
1048
1049 static void
1050 _entry_resized_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1051 {
1052    Evas_Coord en_x, en_y, en_w, en_h;
1053    Evas_Coord bx_x, bx_y;
1054
1055    Widget_Data *wd = elm_widget_data_get(data);
1056    if (!wd) return;
1057
1058    evas_object_geometry_get(wd->entry, &en_x, &en_y, &en_w, &en_h);
1059    evas_object_geometry_get(wd->box, &bx_x, &bx_y, NULL, NULL);
1060
1061    elm_widget_show_region_set(wd->box, en_x - bx_x, en_y - bx_y, en_w, en_h, EINA_TRUE);
1062 }
1063
1064 static void
1065 _view_init(Evas_Object *obj)
1066 {
1067    Widget_Data *wd = elm_widget_data_get(obj);
1068
1069    if (!wd) return;
1070
1071    if (!wd->box)
1072      {
1073         wd->box = elm_box_add (obj);
1074         if (!wd->box) return;
1075         elm_widget_sub_object_add(obj, wd->box);
1076         elm_box_layout_set(wd->box, _box_layout_cb, NULL, NULL);
1077         elm_box_homogeneous_set(wd->box, EINA_FALSE);
1078         edje_object_part_swallow(wd->base, "box.swallow", wd->box);
1079      }
1080    if (!wd->label)
1081      {
1082         wd->label = edje_object_add(evas_object_evas_get(obj));
1083         if (!wd->label) return;
1084         _elm_theme_object_set(obj, wd->label, "multibuttonentry", "label", elm_widget_style_get(obj));
1085         _set_label(obj, "");
1086         elm_widget_sub_object_add(obj, wd->label);
1087      }
1088
1089    if (!wd->entry)
1090      {
1091         if (! (wd->entry = elm_entry_add (obj))) return;
1092         elm_entry_scrollable_set(wd->entry, EINA_TRUE);
1093         elm_entry_single_line_set(wd->entry, EINA_TRUE);
1094         elm_entry_entry_set(wd->entry, "");
1095         elm_entry_cursor_end_set(wd->entry);
1096         elm_entry_input_panel_enabled_set(wd->entry, EINA_FALSE);
1097         evas_object_size_hint_min_set(wd->entry, MIN_W_ENTRY, 0);
1098         evas_object_size_hint_weight_set(wd->entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1099         evas_object_size_hint_align_set(wd->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1100         if (wd->box)   elm_box_pack_end (wd->box, wd->entry);
1101         evas_object_show(wd->entry);
1102         wd->view_state = MULTIBUTTONENTRY_VIEW_ENTRY;
1103      }
1104
1105    if (!wd->end)
1106      {
1107         const char *end_type = edje_object_data_get(wd->base, "closed_button_type");
1108         if (!end_type || !strcmp(end_type, "label"))
1109           {
1110              if (! (wd->end = elm_label_add (obj))) return;
1111              elm_object_style_set(wd->end, "extended/multibuttonentry_default");
1112              wd->end_type = MULTIBUTTONENTRY_CLOSED_LABEL;
1113           }
1114         else
1115           {
1116              const char *size_str;
1117              if (!(wd->end = edje_object_add(evas_object_evas_get(obj)))) return;
1118              _elm_theme_object_set(obj, wd->end, "multibuttonentry", "closedbutton", elm_widget_style_get(obj));
1119              Evas_Coord button_min_width = 0;
1120              Evas_Coord button_min_height = 0;
1121
1122              size_str = edje_object_data_get(wd->end, "closed_button_width");
1123              if(size_str) button_min_width = (Evas_Coord)atoi(size_str);
1124              size_str = edje_object_data_get(wd->end, "closed_button_height");
1125              if(size_str) button_min_height = (Evas_Coord)atoi(size_str);
1126
1127              wd->end_type = MULTIBUTTONENTRY_CLOSED_IMAGE;
1128              evas_object_size_hint_min_set(wd->end, button_min_width * elm_scale_get(), button_min_height * elm_scale_get());
1129              elm_widget_sub_object_add(obj, wd->end);
1130           }
1131      }
1132 }
1133
1134 static void
1135 _calculate_box_min_size(Evas_Object *box, Evas_Object_Box_Data *priv)
1136 {
1137    Evas_Coord minw, minh, maxw, maxh, mnw, mnh, ww;
1138    Evas_Coord w, cw = 0, cmaxh = 0;
1139    const Eina_List *l;
1140    Evas_Object_Box_Option *opt;
1141    double wx;
1142
1143    /* FIXME: need to calc max */
1144    minw = 0;
1145    minh = 0;
1146    maxw = -1;
1147    maxh = -1;
1148
1149    evas_object_geometry_get(box, NULL, NULL, &w, NULL);
1150    evas_object_size_hint_min_get(box, &minw, NULL);
1151
1152    EINA_LIST_FOREACH(priv->children, l, opt)
1153      {
1154         evas_object_size_hint_min_get(opt->obj, &mnw, &mnh);
1155         evas_object_size_hint_weight_get(opt->obj, &wx, NULL);
1156
1157         if (wx)
1158           {
1159              if (mnw != -1 && (w - cw) >= mnw)
1160                ww = w - cw;
1161              else
1162                ww = w;
1163           }
1164         else
1165            ww = mnw;
1166
1167         if ((cw + mnw) > w)
1168           {
1169              minh += cmaxh;
1170              cw = 0;
1171              cmaxh = 0;
1172           }
1173         cw += ww;
1174         if (cmaxh < mnh) cmaxh = mnh;
1175      }
1176
1177    minh += cmaxh;
1178
1179    evas_object_size_hint_min_set(box, minw, minh);
1180 }
1181
1182 static Evas_Coord
1183 _calculate_item_max_height(Evas_Object *box, Evas_Object_Box_Data *priv, int obj_index)
1184 {
1185    Evas_Coord mnw, mnh, cw = 0, cmaxh = 0, w, ww;
1186    const Eina_List *l;
1187    Evas_Object_Box_Option *opt;
1188    int index = 0;
1189    double wx;
1190
1191    evas_object_geometry_get(box, NULL, NULL, &w, NULL);
1192
1193    EINA_LIST_FOREACH(priv->children, l, opt)
1194      {
1195         evas_object_size_hint_min_get(opt->obj, &mnw, &mnh);
1196         evas_object_size_hint_weight_get(opt->obj, &wx, NULL);
1197
1198         if (wx)
1199           {
1200              if (mnw != -1 && (w - cw) >= mnw)
1201                 ww = w - cw;
1202              else
1203                 ww = w;
1204           }
1205         else
1206            ww = mnw;
1207
1208         if ((cw + ww) > w)
1209           {
1210              if (index > obj_index) return cmaxh;
1211              cw = 0;
1212              cmaxh = 0;
1213           }
1214
1215         cw += ww;
1216         if (cmaxh < mnh) cmaxh = mnh;
1217
1218         index++;
1219      }
1220
1221    return cmaxh;
1222 }
1223
1224 static void
1225 _box_layout_cb(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1226 {
1227    Evas_Coord x, y, w, h, xx, yy;
1228    const Eina_List *l;
1229    Evas_Object *obj;
1230    Evas_Coord minw, minh, wdif, hdif;
1231    int count = 0;
1232    double ax, ay;
1233    Evas_Object_Box_Option *opt;
1234
1235    _calculate_box_min_size(o, priv);
1236
1237    evas_object_geometry_get(o, &x, &y, &w, &h);
1238
1239    evas_object_size_hint_min_get(o, &minw, &minh);
1240    evas_object_size_hint_align_get(o, &ax, &ay);
1241    count = eina_list_count(priv->children);
1242    if (w < minw)
1243      {
1244         x = x + ((w - minw) * (1.0 - ax));
1245         w = minw;
1246      }
1247    if (h < minh)
1248      {
1249         y = y + ((h - minh) * (1.0 - ay));
1250         h = minh;
1251      }
1252
1253    wdif = w - minw;
1254    hdif = h - minh;
1255    xx = x;
1256    yy = y;
1257
1258    Evas_Coord cw = 0, ch = 0, cmaxh = 0, obj_index = 0;
1259
1260    EINA_LIST_FOREACH(priv->children, l, opt)
1261      {
1262         Evas_Coord mnw, mnh, mxw, mxh;
1263         double wx, wy;
1264         int fw, fh, xw, xh;
1265
1266         obj = opt->obj;
1267         evas_object_size_hint_align_get(obj, &ax, &ay);
1268         evas_object_size_hint_weight_get(obj, &wx, &wy);
1269         evas_object_size_hint_min_get(obj, &mnw, &mnh);
1270         evas_object_size_hint_max_get(obj, &mxw, &mxh);
1271         fw = fh = 0;
1272         xw = xh = 0;
1273         if (ax == -1.0) {fw = 1; ax = 0.5;}
1274         if (ay == -1.0) {fh = 1; ay = 0.5;}
1275         if (wx > 0.0) xw = 1;
1276         if (wy > 0.0) xh = 1;
1277         Evas_Coord ww, hh, ow, oh;
1278
1279         if (wx)
1280           {
1281              if (mnw != -1 && (w - cw) >= mnw)
1282                 ww = w - cw;
1283              else
1284                 ww = w;
1285           }
1286         else
1287            ww = mnw;
1288         hh = _calculate_item_max_height(o, priv, obj_index);
1289
1290         ow = mnw;
1291         if (fw) ow = ww;
1292         if ((mxw >= 0) && (mxw < ow)) ow = mxw;
1293         oh = mnh;
1294         if (fh) oh = hh;
1295         if ((mxh >= 0) && (mxh < oh)) oh = mxh;
1296
1297         if ((cw + ww) > w)
1298           {
1299              ch += cmaxh;
1300              cw = 0;
1301              cmaxh = 0;
1302           }
1303
1304         evas_object_move(obj,
1305                          xx + cw + (Evas_Coord)(((double)(ww - ow)) * ax),
1306                          yy + ch + (Evas_Coord)(((double)(hh - oh)) * ay));
1307         evas_object_resize(obj, ow, oh);
1308
1309         cw += ww;
1310         if (cmaxh < hh) cmaxh = hh;
1311
1312         obj_index++;
1313      }
1314 }
1315
1316 EAPI Evas_Object *
1317 elm_multibuttonentry_add(Evas_Object *parent)
1318 {
1319    Evas_Object *obj;
1320    Evas *e;
1321    Widget_Data *wd;
1322
1323    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1324
1325    ELM_SET_WIDTYPE(widtype, "multibuttonentry");
1326    elm_widget_type_set(obj, "multibuttonentry");
1327    elm_widget_sub_object_add(parent, obj);
1328    elm_widget_data_set(obj, wd);
1329
1330    elm_widget_del_hook_set(obj, _del_hook);
1331    elm_widget_theme_hook_set(obj, _theme_hook);
1332    elm_widget_event_hook_set(obj, _event_hook);
1333    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1334    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1335
1336    wd->base = edje_object_add(e);
1337    _elm_theme_object_set(obj, wd->base, "multibuttonentry", "base", "default");
1338    elm_widget_resize_object_set(obj, wd->base);
1339    elm_widget_can_focus_set(obj, EINA_TRUE);
1340
1341    wd->view_state = MULTIBUTTONENTRY_VIEW_NONE;
1342    wd->focused = EINA_FALSE;
1343    wd->last_btn_select = EINA_TRUE;
1344    wd->n_str = 0;
1345    wd->rect_for_end= NULL;
1346    wd->add_callback = NULL;
1347    wd->add_callback_data = NULL;
1348
1349    _view_init(obj);
1350    _event_init(obj);
1351
1352    return obj;
1353 }
1354
1355 EAPI Evas_Object *
1356 elm_multibuttonentry_entry_get(const Evas_Object *obj)
1357 {
1358    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1359    Widget_Data *wd = elm_widget_data_get(obj);
1360
1361    if (!wd) return NULL;
1362
1363    return wd->entry;
1364 }
1365
1366 EAPI const char *
1367 elm_multibuttonentry_label_get(const Evas_Object *obj)
1368 {
1369    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1370    Widget_Data *wd = elm_widget_data_get(obj);
1371
1372    if (!wd) return NULL;
1373    if (wd->label) return edje_object_part_text_get(wd->label, "mbe.label");
1374    return NULL;
1375 }
1376
1377 EAPI void
1378 elm_multibuttonentry_label_set(Evas_Object *obj, const char *label)
1379 {
1380    ELM_CHECK_WIDTYPE(obj, widtype);
1381    Widget_Data *wd = elm_widget_data_get(obj);
1382
1383    if (!wd) return;
1384    if (label)
1385      _set_label(obj, label);
1386    else
1387      _set_label(obj, "");
1388 }
1389
1390 EAPI const char *
1391 elm_multibuttonentry_guide_text_get(const Evas_Object *obj)
1392 {
1393    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1394    Widget_Data *wd = elm_widget_data_get(obj);
1395
1396    if (!wd) return NULL;
1397    if (wd->guidetext) return edje_object_part_text_get(wd->guidetext, "elm.text");
1398    return NULL;
1399 }
1400
1401 EAPI void
1402 elm_multibuttonentry_guide_text_set(Evas_Object *obj, const char *guidetext)
1403 {
1404    ELM_CHECK_WIDTYPE(obj, widtype);
1405    Widget_Data *wd = elm_widget_data_get(obj);
1406
1407    if (!wd) return;
1408    if (guidetext)
1409      _set_guidetext(obj, guidetext);
1410    else
1411      _set_guidetext(obj, "");
1412 }
1413
1414 EAPI int
1415 elm_multibuttonentry_contracted_state_get(const Evas_Object *obj)
1416 {
1417    ELM_CHECK_WIDTYPE(obj, widtype) -1;
1418    Widget_Data *wd = elm_widget_data_get(obj);
1419
1420    if (!wd) return -1;
1421    return wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED ? 1 : 0;
1422 }
1423
1424 EAPI void
1425 elm_multibuttonentry_contracted_state_set(Evas_Object *obj, int contracted)
1426 {
1427    ELM_CHECK_WIDTYPE(obj, widtype);
1428    Widget_Data *wd = elm_widget_data_get(obj);
1429
1430    if (!wd || !wd->box ||
1431        ((wd->view_state == MULTIBUTTONENTRY_VIEW_CONTRACTED) ? 1 : 0) == contracted) return;
1432    _contracted_state_set(obj, contracted);
1433 }
1434
1435 EAPI Elm_Multibuttonentry_Item *
1436 elm_multibuttonentry_item_add_start(Evas_Object *obj, const char *label, void *data)
1437 {
1438    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1439    Widget_Data *wd = elm_widget_data_get(obj);
1440    Elm_Multibuttonentry_Item *item;
1441
1442    if (!wd || !label) return NULL;
1443    item = _add_button_item(obj, label, MULTIBUTTONENTRY_POS_START, NULL, data);
1444    return item;
1445 }
1446
1447 EAPI Elm_Multibuttonentry_Item *
1448 elm_multibuttonentry_item_add_end(Evas_Object *obj, const char *label, void *data)
1449 {
1450    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1451    Widget_Data *wd = elm_widget_data_get(obj);
1452    Elm_Multibuttonentry_Item *item;
1453
1454    if (!wd || !label) return NULL;
1455    item = _add_button_item(obj, label, MULTIBUTTONENTRY_POS_END, NULL, data);
1456    return item;
1457 }
1458
1459 EAPI Elm_Multibuttonentry_Item *
1460 elm_multibuttonentry_item_add_before(Evas_Object *obj, const char *label, Elm_Multibuttonentry_Item *before, void *data)
1461 {
1462    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1463    Widget_Data *wd = elm_widget_data_get(obj);
1464    Elm_Multibuttonentry_Item *item;
1465
1466    if (!wd || !label) return NULL;
1467    item = _add_button_item(obj, label, MULTIBUTTONENTRY_POS_BEFORE, before, data);
1468    return item;
1469 }
1470
1471 EAPI Elm_Multibuttonentry_Item *
1472 elm_multibuttonentry_item_add_after(Evas_Object *obj, const char *label, Elm_Multibuttonentry_Item *after, void *data)
1473 {
1474    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1475    Widget_Data *wd = elm_widget_data_get(obj);
1476    Elm_Multibuttonentry_Item *item;
1477
1478    if (!wd || !label) return NULL;
1479    item = _add_button_item(obj, label, MULTIBUTTONENTRY_POS_AFTER, after, data);
1480    return item;
1481 }
1482
1483 EAPI const Eina_List *
1484 elm_multibuttonentry_items_get(const Evas_Object *obj)
1485 {
1486    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1487    Widget_Data *wd = elm_widget_data_get(obj);
1488
1489    if (!wd) return NULL;
1490    return wd->items;
1491 }
1492
1493 EAPI Elm_Multibuttonentry_Item *
1494 elm_multibuttonentry_item_first_get(const Evas_Object *obj)
1495 {
1496    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1497    Widget_Data *wd = elm_widget_data_get(obj);
1498
1499    if (!wd || !wd->items) return NULL;
1500    return eina_list_data_get(wd->items);
1501 }
1502
1503 EAPI Elm_Multibuttonentry_Item *
1504 elm_multibuttonentry_item_last_get(const Evas_Object *obj)
1505 {
1506    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1507    Widget_Data *wd = elm_widget_data_get(obj);
1508
1509    if (!wd || !wd->items) return NULL;
1510    return eina_list_data_get(eina_list_last(wd->items));
1511 }
1512
1513 EAPI Elm_Multibuttonentry_Item *
1514 elm_multibuttonentry_item_selected_get(const Evas_Object *obj)
1515 {
1516    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1517    Widget_Data *wd = elm_widget_data_get(obj);
1518
1519    if (!wd || !wd->current) return NULL;
1520    return eina_list_data_get(wd->current);
1521 }
1522
1523 EAPI void
1524 elm_multibuttonentry_item_selected_set(Elm_Multibuttonentry_Item *item)
1525 {
1526    Widget_Data *wd;
1527    Eina_List *l;
1528    Elm_Multibuttonentry_Item *_item;
1529
1530    if (!item) return;
1531    ELM_CHECK_WIDTYPE(item->multibuttonentry, widtype);
1532    wd = elm_widget_data_get(item->multibuttonentry);
1533    if (!wd) return;
1534
1535    EINA_LIST_FOREACH(wd->items, l, _item)
1536      {
1537         if (_item == item)
1538           _select_button(item->multibuttonentry, item->button);
1539      }
1540 }
1541
1542 EAPI void
1543 elm_multibuttonentry_item_unselect_all(Evas_Object *obj)
1544 {
1545    ELM_CHECK_WIDTYPE(obj, widtype);
1546    Widget_Data *wd = elm_widget_data_get(obj);
1547    if (!wd) return;
1548
1549    _select_button(obj, NULL);
1550 }
1551
1552 EAPI void
1553 elm_multibuttonentry_items_del(Evas_Object *obj)
1554 {
1555    ELM_CHECK_WIDTYPE(obj, widtype);
1556    Widget_Data *wd = elm_widget_data_get(obj);
1557    if (!wd) return;
1558
1559    if (wd->items)
1560      {
1561         Elm_Multibuttonentry_Item *item;
1562         EINA_LIST_FREE(wd->items, item)
1563           {
1564              elm_box_unpack(wd->box, item->button);
1565              _del_button_obj(obj, item->button);
1566              free(item);
1567           }
1568         wd->items = NULL;
1569      }
1570    wd->current = NULL;
1571    _view_update(obj);
1572 }
1573
1574 EAPI void
1575 elm_multibuttonentry_item_del(Elm_Multibuttonentry_Item *item)
1576 {
1577    if (!item) return;
1578    _del_button_item(item);
1579 }
1580
1581 EAPI const char *
1582 elm_multibuttonentry_item_label_get(const Elm_Multibuttonentry_Item *item)
1583 {
1584    Widget_Data *wd;
1585    Eina_List *l;
1586    Elm_Multibuttonentry_Item *_item;
1587    if (!item) return NULL;
1588    ELM_CHECK_WIDTYPE(item->multibuttonentry, widtype) NULL;
1589    wd = elm_widget_data_get(item->multibuttonentry);
1590    if (!wd || !wd->items) return NULL;
1591
1592    EINA_LIST_FOREACH(wd->items, l, _item)
1593      {
1594         if (_item == item)
1595           return edje_object_part_text_get(_item->button, "elm.btn.text");
1596      }
1597
1598    return NULL;
1599 }
1600
1601 EAPI void
1602 elm_multibuttonentry_item_label_set(Elm_Multibuttonentry_Item *item, const char *str)
1603 {
1604    Widget_Data *wd;
1605    Eina_List *l;
1606    Elm_Multibuttonentry_Item *_item;
1607    if (!item || !str) return;
1608    ELM_CHECK_WIDTYPE(item->multibuttonentry, widtype);
1609    wd = elm_widget_data_get(item->multibuttonentry);
1610    if (!wd || !wd->items) return;
1611
1612    EINA_LIST_FOREACH(wd->items, l, _item)
1613      if (_item == item)
1614        {
1615           edje_object_part_text_set(_item->button, "elm.btn.text", str);
1616           _resize_button(_item->button, &_item->rw, &_item->vw);
1617           break;
1618        }
1619 }
1620
1621 EAPI Elm_Multibuttonentry_Item *
1622 elm_multibuttonentry_item_prev(Elm_Multibuttonentry_Item *item)
1623 {
1624    Widget_Data *wd;
1625    Eina_List *l;
1626    Elm_Multibuttonentry_Item *_item;
1627    if (!item) return NULL;
1628    ELM_CHECK_WIDTYPE(item->multibuttonentry, widtype) NULL;
1629    wd = elm_widget_data_get(item->multibuttonentry);
1630    if (!wd || !wd->items) return NULL;
1631
1632    EINA_LIST_FOREACH(wd->items, l, _item)
1633       if (_item == item)
1634         {
1635            l = eina_list_prev(l);
1636            if (!l) return NULL;
1637            return eina_list_data_get(l);
1638         }
1639    return NULL;
1640 }
1641
1642 EAPI Elm_Multibuttonentry_Item *
1643 elm_multibuttonentry_item_next(Elm_Multibuttonentry_Item *item)
1644 {
1645    Widget_Data *wd;
1646    Eina_List *l;
1647    Elm_Multibuttonentry_Item *_item;
1648
1649    if (!item) return NULL;
1650    ELM_CHECK_WIDTYPE(item->multibuttonentry, widtype) NULL;
1651    wd = elm_widget_data_get(item->multibuttonentry);
1652    if (!wd || !wd->items) return NULL;
1653
1654    EINA_LIST_FOREACH(wd->items, l, _item)
1655       if (_item == item)
1656         {
1657            l = eina_list_next(l);
1658            if (!l) return NULL;
1659            return eina_list_data_get(l);
1660         }
1661    return NULL;
1662 }
1663
1664 EAPI void *
1665 elm_multibuttonentry_item_data_get(const Elm_Multibuttonentry_Item *item)
1666 {
1667    if (!item) return NULL;
1668    return item->data;
1669 }
1670
1671 EAPI void
1672 elm_multibuttonentry_item_data_set(Elm_Multibuttonentry_Item *item, void *data)
1673 {
1674    if (!item) return;
1675    item->data = data;
1676 }
1677
1678 EAPI void
1679 elm_multibuttonentry_item_verify_callback_set(Evas_Object *obj, Elm_Multibuttonentry_Item_Verify_Callback func, void *data)
1680 {
1681    ELM_CHECK_WIDTYPE(obj, widtype);
1682    Widget_Data *wd = elm_widget_data_get(obj);
1683    if (!wd) return;
1684
1685    wd->add_callback = func;
1686    wd->add_callback_data = data;
1687 }