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