[elm_ctxpopup] updated for stability
[framework/uifw/elementary.git] / src / lib / elm_ctxpopup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Ctxpopup Ctxpopup
6  * @ingroup Elementary
7  *
8  * Contextual popup.
9  *
10  * Signals that you can add callbacks for are:
11  *
12  * hide - This is emitted when the ctxpopup is hided.
13  *
14  */
15
16 typedef struct _Widget_Data Widget_Data;
17
18 struct _Ctxpopup_Item {
19         Evas_Object *ctxpopup;
20         Evas_Object *base;
21         const char *label;
22         Evas_Object *icon;
23         void (*func)(void *data, Evas_Object * obj, void *event_info);
24         void *data;
25         Eina_Bool disabled :1;
26         Eina_Bool separator :1;
27 };
28
29 struct _Widget_Data {
30         Evas_Object *parent;
31         Evas_Object *base;
32         Evas_Object *content;
33         Evas_Object *box;
34         Evas_Object *arrow;
35         Evas_Object *scroller;
36         Evas_Object *bg;
37         Evas_Object *btn_layout;
38         Evas_Object *area_rect;
39         Eina_List *items;
40         Elm_Ctxpopup_Arrow arrow_dir;
41         Elm_Ctxpopup_Arrow arrow_priority[4];
42         int btn_cnt;
43         Elm_Transit *transit;
44         Evas_Coord max_sc_w, max_sc_h;
45         char *title;
46         Eina_Bool scroller_disabled :1;
47         Eina_Bool horizontal :1;
48         Eina_Bool visible :1;
49         Eina_Bool screen_dimmed_disabled :1;
50         Eina_Bool position_forced :1;
51         Eina_Bool finished :1;
52 };
53
54 static const char *widtype = NULL;
55 static void _del_hook(Evas_Object *obj);
56 static void _del_pre_hook(Evas_Object *obj);
57 static void _theme_hook(Evas_Object *obj);
58 static void _sizing_eval(Evas_Object *obj);
59 static void _area_rect_resize(void *data, Evas *e, Evas_Object *obj,
60                 void *event_info);
61 static void _area_rect_move(void *data, Evas *e, Evas_Object *obj,
62                 void *event_info);
63 static void _area_rect_del(void *data, Evas *e, Evas_Object *obj,
64                 void *event_info);
65 static void _bg_clicked_cb(void *data, Evas_Object *obj, const char *emission,
66                 const char *source);
67 static void _parent_resize(void *data, Evas *e, Evas_Object *obj,
68                 void *event_info);
69 static void _ctxpopup_show(void *data, Evas *e, Evas_Object *obj,
70                 void *event_info);
71 static void _ctxpopup_hide(void *data, Evas *e, Evas_Object *obj,
72                 void *event_info);
73 static void _ctxpopup_move(void *data, Evas *e, Evas_Object *obj,
74                 void *event_info);
75 static void _ctxpopup_changed_size_hints(void *data, Evas *e, Evas_Object *obj, 
76                 void *event_info);
77 static void _ctxpopup_scroller_resize(void *data, Evas *e, Evas_Object *obj,
78                 void *event_info);
79 static void _item_obj_create(Elm_Ctxpopup_Item *item, char *group_name);
80 static void _item_sizing_eval(Elm_Ctxpopup_Item *item);
81 static void _ctxpopup_item_select(void *data, Evas_Object *obj,
82                 const char *emission, const char *source);
83 static void _separator_obj_add(Evas_Object *obj);
84 static void _separator_obj_del(Widget_Data *wd, Elm_Ctxpopup_Item *remove_item);
85 static Elm_Ctxpopup_Arrow _calc_base_geometry(Evas_Object *obj,
86                 Evas_Coord_Rectangle *rect);
87 static void _update_arrow_obj(Evas_Object *obj, Elm_Ctxpopup_Arrow arrow_dir);
88 static void _shift_base_by_arrow(Evas_Object *arrow,
89                 Elm_Ctxpopup_Arrow arrow_dir, Evas_Coord_Rectangle *rect);
90 static void _btn_layout_create(Evas_Object *obj);
91 static int _get_indicator_h(Evas_Object *parent);
92 static void _delete_area_rect_callbacks(Widget_Data *wd);
93 static void _adjust_pos_x(Evas_Coord_Point *pos, Evas_Coord_Point *base_size,
94                 Evas_Coord_Rectangle *area_rect);
95 static void _adjust_pos_y(int indicator_h, Evas_Coord_Point *pos,
96                 Evas_Coord_Point *base_size, Evas_Coord_Rectangle *area_rect);
97 static void _reset_scroller_size(Widget_Data *wd);
98 static void _hide_ctxpopup(Evas_Object *obj);
99 static void _content_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
100 static void _content_changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
101
102 static void _reset_scroller_size(Widget_Data *wd)
103 {
104         wd->finished = EINA_FALSE;
105         wd->max_sc_h = -1;
106         wd->max_sc_w = -1;
107 }
108
109 static void _delete_area_rect_callbacks(Widget_Data *wd) 
110 {
111         if (!wd->area_rect) return;
112
113         evas_object_event_callback_del(wd->area_rect, EVAS_CALLBACK_DEL,
114                         _area_rect_del);
115         evas_object_event_callback_del(wd->area_rect, EVAS_CALLBACK_MOVE,
116                         _area_rect_move);
117         evas_object_event_callback_del(wd->area_rect, EVAS_CALLBACK_RESIZE,
118                         _area_rect_resize);
119 }
120
121 static void _area_rect_resize(void *data, Evas *e, Evas_Object *obj,    void *event_info) 
122 {
123         Widget_Data *wd = elm_widget_data_get(data);
124         if(wd->visible) {
125                 _reset_scroller_size(wd);
126                 _sizing_eval(obj);
127         }
128 }
129
130 static void _area_rect_move(void *data, Evas *e, Evas_Object *obj, void *event_info) 
131 {
132         Widget_Data *wd = elm_widget_data_get(data);
133         if(wd->visible) {
134                 _reset_scroller_size(wd);
135                 _sizing_eval(obj);
136         }
137 }
138
139 static void _area_rect_del(void *data, Evas *e, Evas_Object *obj, void *event_info) 
140 {
141         Widget_Data *wd = elm_widget_data_get(data);
142         wd->area_rect = NULL;
143 }
144
145 static void _show_effect_done(void *data, Elm_Transit *transit) 
146 {
147         //TODO: Consider implementing effect in edc.
148         Widget_Data *wd = data;
149         elm_transit_fx_clear(transit);
150
151         if (wd->box)
152                 elm_transit_fx_insert(transit, elm_fx_color_add(wd->box, 0, 0, 0, 0,
153                                 255, 255, 255, 255));
154         if (wd->content)
155                 elm_transit_fx_insert(transit, elm_fx_color_add(wd->content, 0, 0, 0,
156                                 0, 255, 255, 255, 255));
157         if (wd->btn_layout)
158                 elm_transit_fx_insert(transit, elm_fx_color_add(wd->btn_layout, 0, 0,
159                                 0, 0, 255, 255, 255, 255));
160         elm_transit_run(transit, 0.2);
161         elm_transit_completion_callback_set(transit, NULL, NULL);
162         elm_transit_del(transit);
163         wd->transit = NULL;
164         edje_object_signal_emit(wd->base, "elm,state,show", "elm");
165 }
166
167 static void _show_effect(Widget_Data* wd) 
168 {
169         //TODO: Consider implementing effect in edc.
170         if (wd->transit) {
171                 elm_transit_stop(wd->transit);
172                 elm_transit_fx_clear(wd->transit);
173         } else {
174                 wd->transit = elm_transit_add(wd->base);
175                 elm_transit_curve_style_set(wd->transit, ELM_ANIMATOR_CURVE_OUT);
176                 elm_transit_completion_callback_set(wd->transit, _show_effect_done, wd);
177         }
178
179         elm_transit_fx_insert(wd->transit, elm_fx_color_add(wd->base, 0, 0, 0, 0,
180                         255, 255, 255, 255));
181         elm_transit_fx_insert(wd->transit, elm_fx_wipe_add(wd->base,
182                         ELM_FX_WIPE_TYPE_SHOW, wd->arrow_dir));
183
184         if(!wd->position_forced)
185                 elm_transit_fx_insert(wd->transit, elm_fx_color_add(wd->arrow, 0, 0, 0, 0, 255, 255, 255, 255));
186
187         if (wd->box)
188                 evas_object_color_set(wd->box, 0, 0, 0, 0);
189         if (wd->content)
190                 evas_object_color_set(wd->content, 0, 0, 0, 0);
191         if (wd->btn_layout)
192                 evas_object_color_set(wd->btn_layout, 0, 0, 0, 0);
193
194         elm_transit_run(wd->transit, 0.3);
195 }
196
197 static void _hide_effect_done(void *data, Elm_Transit *transit)
198 {
199         //TODO: Consider implementing effect in edc.
200         Widget_Data *wd = elm_widget_data_get(data);
201         if(!wd) return ;
202         elm_transit_del(transit);
203         wd->transit = NULL;
204         _hide_ctxpopup(data);
205 }
206
207 static void _hide_effect(Evas_Object *obj)
208 {
209         //TODO: Consider implementing effect in edc.
210         Widget_Data *wd = elm_widget_data_get(obj);
211         if(!wd) return;
212
213         if (wd->transit) {
214                 elm_transit_stop(wd->transit);
215                 elm_transit_fx_clear(wd->transit);
216         } else {
217                 wd->transit = elm_transit_add(wd->base);
218                 elm_transit_curve_style_set(wd->transit, ELM_ANIMATOR_CURVE_OUT);
219                 elm_transit_completion_callback_set(wd->transit, _hide_effect_done, obj);
220         }
221
222 //      elm_transit_fx_insert(wd->transit, elm_fx_color_add(wd->base, 255, 255, 255, 255, 0, 0, 0, 0));
223
224         switch(wd->arrow_dir) {
225                 case  ELM_FX_WIPE_DIR_UP:
226                         elm_transit_fx_insert(wd->transit, elm_fx_wipe_add(wd->base, ELM_FX_WIPE_TYPE_HIDE, ELM_FX_WIPE_DIR_DOWN));
227                         break;
228                 case  ELM_FX_WIPE_DIR_LEFT:
229                         elm_transit_fx_insert(wd->transit, elm_fx_wipe_add(wd->base, ELM_FX_WIPE_TYPE_HIDE, ELM_FX_WIPE_DIR_RIGHT));
230                         break;
231                 case  ELM_FX_WIPE_DIR_RIGHT:
232                         elm_transit_fx_insert(wd->transit, elm_fx_wipe_add(wd->base, ELM_FX_WIPE_TYPE_HIDE, ELM_FX_WIPE_DIR_LEFT));
233                         break;
234                 case  ELM_FX_WIPE_DIR_DOWN:
235                         elm_transit_fx_insert(wd->transit, elm_fx_wipe_add(wd->base, ELM_FX_WIPE_TYPE_HIDE, ELM_FX_WIPE_DIR_UP));
236                         break;
237                 default:
238                         break;
239         }
240
241         elm_transit_run(wd->transit, 0.3);
242 }
243
244 static void _separator_obj_del(Widget_Data *wd, Elm_Ctxpopup_Item *remove_item) 
245 {
246         Eina_List *elist, *cur_list, *prev_list;
247         Elm_Ctxpopup_Item *separator;
248
249         if ((!remove_item) || (!wd)) return;
250
251         elist = wd->items;
252         cur_list = eina_list_data_find_list(elist, remove_item);
253
254         if (!cur_list)  return;
255
256         prev_list = eina_list_prev(cur_list);
257         
258         if (!prev_list) return;
259
260         separator = (Elm_Ctxpopup_Item *) eina_list_data_get(prev_list);
261         
262         if (!separator)return;
263         
264         wd->items = eina_list_remove(wd->items, separator);
265         evas_object_del(separator->base);
266         free(separator);
267 }
268
269 static void _btn_layout_create(Evas_Object *obj) 
270 {
271         Widget_Data *wd = elm_widget_data_get(obj);
272
273         wd->btn_layout = edje_object_add(evas_object_evas_get(obj));
274         elm_widget_sub_object_add(obj, wd->btn_layout);
275         edje_object_signal_emit(wd->base, "elm,state,buttons,enable", "elm");
276         edje_object_part_swallow(wd->base, "elm.swallow.btns", wd->btn_layout);
277 }
278
279 static void _separator_obj_add(Evas_Object *obj) 
280 {
281         Elm_Ctxpopup_Item *item;
282
283         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
284
285         if (!wd) return;
286         if (eina_list_count(wd->items) == 0) return;
287
288         item = ELM_NEW(Elm_Ctxpopup_Item);
289         if (!item) return;
290
291         item->base = edje_object_add(evas_object_evas_get(wd->base));
292
293         if (!item->base) {
294                 free(item);
295                 return;
296         }
297
298         _elm_theme_object_set(obj, item->base, "ctxpopup", "separator",
299                         elm_widget_style_get(obj));
300
301         if (wd->horizontal)
302                 edje_object_signal_emit(item->base, "elm,state,horizontal", "elm");
303         else
304                 edje_object_signal_emit(item->base, "elm,state,vertical", "elm");
305
306         evas_object_size_hint_align_set(item->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
307         evas_object_show(item->base);
308         item->separator = EINA_TRUE;
309         elm_box_pack_end(wd->box, item->base);
310         wd->items = eina_list_append(wd->items, item);
311 }
312
313 static void _item_sizing_eval(Elm_Ctxpopup_Item *item) 
314 {
315         Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
316         Evas_Coord x, y, w, h;
317
318         if (!item) return;
319
320         if (!item->separator) elm_coords_finger_size_adjust(1, &min_w, 1, &min_h);
321
322         evas_object_geometry_get(item->base, &x, &y, &w, &h);
323         edje_object_size_min_restricted_calc(item->base, &min_w, &min_h, min_w, min_h);
324         evas_object_size_hint_min_set(item->base, min_w, min_h);
325         evas_object_size_hint_max_set(item->base, max_w, max_h);
326 }
327
328 static void _adjust_pos_x(Evas_Coord_Point *pos, Evas_Coord_Point *base_size,
329                 Evas_Coord_Rectangle *area_rect) 
330 {
331         pos->x -= (base_size->x / 2);
332
333         if (pos->x < area_rect->x) pos->x = area_rect->x;
334         else if ((pos->x + base_size->x) > (area_rect->x + area_rect->w)) 
335                 pos->x = (area_rect->x + area_rect->w) - base_size->x;
336
337         if (base_size->x > area_rect->w)
338                 base_size->x -= (base_size->x - area_rect->w);
339         if (pos->x < area_rect->x)
340                 pos->x = area_rect->x;
341 }
342
343 static void _adjust_pos_y(int indicator_h, Evas_Coord_Point *pos,
344                 Evas_Coord_Point *base_size, Evas_Coord_Rectangle *area_rect) 
345 {
346         pos->y -= (base_size->y / 2);
347
348         if (pos->y < area_rect->y) pos->y = area_rect->y;
349         else if ((pos->y + base_size->y) > (area_rect->y + area_rect->h)) 
350                 pos->y = area_rect->y + area_rect->h - base_size->y;
351
352         if (base_size->y > area_rect->h) 
353                 base_size->y -= (base_size->y - area_rect->h);
354         
355         if (pos->y < area_rect->y) pos->y = area_rect->y;
356 }
357
358 static int _get_indicator_h(Evas_Object *parent) 
359 {
360         Ecore_X_Window zone, xwin;
361         int h = 0;
362
363         if (elm_win_indicator_state_get(parent) != 1) 
364                 return 0;
365
366         xwin = elm_win_xwindow_get(parent);
367         zone = ecore_x_e_illume_zone_get(xwin);
368         ecore_x_e_illume_indicator_geometry_get(zone, NULL, NULL, NULL, &h);
369
370         return h;
371 }
372
373 static void _ctxpopup_changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info)
374 {
375         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
376         if (!wd) return;
377         if(wd->visible)_sizing_eval(obj);
378 }
379
380 static Elm_Ctxpopup_Arrow _calc_base_geometry(Evas_Object *obj, Evas_Coord_Rectangle *rect) 
381 {
382         Widget_Data *wd;
383         Evas_Coord_Point pos;
384         Evas_Coord_Point base_size;
385         Evas_Coord_Point max_size;
386         Evas_Coord_Point min_size;
387         Evas_Coord_Rectangle area_rect;
388         Evas_Coord_Point parent_size;
389         Evas_Coord_Point arrow_size;
390         Elm_Ctxpopup_Arrow arrow;
391         Evas_Coord finger_size;
392         Evas_Coord indicator_h;
393         Evas_Coord_Point temp;
394         Evas_Coord min_calc_h;
395         Evas_Coord min_calc_w;
396         int idx;
397
398         wd = elm_widget_data_get(obj);
399
400         if ((!wd) || (!rect)) return ELM_CTXPOPUP_ARROW_DOWN;
401
402         indicator_h = _get_indicator_h(wd->parent);
403         finger_size = elm_finger_size_get();
404
405         edje_object_part_geometry_get(wd->arrow, "ctxpopup_arrow", NULL, NULL,
406                         &arrow_size.x, &arrow_size.y);
407         evas_object_resize(wd->arrow, arrow_size.x, arrow_size.y);
408
409         //Initialize Area Rectangle. 
410         if (wd->area_rect)
411                 evas_object_geometry_get(wd->area_rect, &area_rect.x, &area_rect.y,
412                                 &area_rect.w, &area_rect.h);
413         else {
414                 evas_object_geometry_get(wd->parent, NULL, NULL, &parent_size.x, &parent_size.y);
415                 area_rect.x = 0;
416                 area_rect.y = 0;
417                 area_rect.w = parent_size.x;
418                 area_rect.h = parent_size.y;
419         }
420
421         if (area_rect.y < indicator_h) {
422                 temp.y = indicator_h - area_rect.y;
423                 area_rect.y = indicator_h;
424                 area_rect.h -= temp.y;
425         }
426         
427         evas_object_geometry_get(obj, &pos.x, &pos.y, NULL, NULL);
428         edje_object_size_min_calc(wd->base, &base_size.x, &base_size.y);
429
430         min_calc_w = base_size.x;
431         min_calc_h = base_size.y;
432
433         //Limit to Max Size
434         evas_object_size_hint_max_get(obj, &max_size.x, &max_size.y);
435         
436         if( max_size.y > 0 ) 
437                 if(base_size.y > max_size.y) base_size.y = max_size.y;
438
439         if( max_size.x > 0 ) 
440                 if(base_size.x > max_size.x) base_size.x = max_size.x;
441
442         //Limit to Min Size 
443         evas_object_size_hint_min_get(obj, &min_size.x, &min_size.y);
444         
445         if( min_size.y > 0 ) { 
446                 if(base_size.y < min_size.y) base_size.y = min_size.y;
447                 if(min_calc_h <  min_size.y) min_calc_h = min_size.y;
448         }
449                 
450         if( min_size.x > 0 ) {
451                 if(base_size.x < min_size.x) base_size.x = min_size.x;
452                 if(min_calc_w <  min_size.x) min_calc_w = min_size.x;
453         }
454
455         //In case of position forced. It shows up just like popup.  
456         if (wd->position_forced) {
457                 //TODO: calculate the size of ctxpopup
458                 rect->x = pos.x;
459                 rect->y = pos.y;
460                 rect->w = base_size.x;
461                 rect->h = base_size.y;
462                 return ELM_CTXPOPUP_ARROW_UP;
463         }
464
465         //Check the Which direction is available.
466         //If find a avaialble direction, it adjusts position and size. 
467         for (idx = 0; idx < 4; ++idx) {
468                 switch (wd->arrow_priority[idx]) {
469                         case ELM_CTXPOPUP_ARROW_DOWN:
470                                 temp.y = pos.y - base_size.y;
471                                 if ((temp.y - arrow_size.y - finger_size) < area_rect.y) continue;
472                                 _adjust_pos_x(&pos, &base_size, &area_rect);
473                                 pos.y -= (base_size.y + finger_size);
474                                 arrow = ELM_CTXPOPUP_ARROW_DOWN;
475                                 break;
476                         case ELM_CTXPOPUP_ARROW_RIGHT:
477                                 temp.x = (pos.x - base_size.x);
478                                 if ((temp.x - arrow_size.x - finger_size) < area_rect.x) continue;
479                                 _adjust_pos_y(indicator_h, &pos, &base_size, &area_rect);
480                                 pos.x -= (base_size.x + finger_size);
481                                 arrow = ELM_CTXPOPUP_ARROW_RIGHT;
482                                 break;
483                         case ELM_CTXPOPUP_ARROW_LEFT:
484                                 temp.x = (pos.x + base_size.x);
485                                 if ((temp.x + arrow_size.x + finger_size) > (area_rect.x        + area_rect.w)) continue;
486                                 _adjust_pos_y(indicator_h, &pos, &base_size, &area_rect);
487                                 pos.x += finger_size;
488                                 arrow = ELM_CTXPOPUP_ARROW_LEFT;
489                                 break;
490                         case ELM_CTXPOPUP_ARROW_UP:
491                                 temp.y = (pos.y + base_size.y);
492                                 if ((temp.y + arrow_size.y + finger_size) > (area_rect.y + area_rect.h)) continue;
493                                 _adjust_pos_x(&pos, &base_size, &area_rect);
494                                 pos.y += finger_size;
495                                 arrow = ELM_CTXPOPUP_ARROW_UP;
496                                 break;
497                         default:
498                                 break;
499                 }
500                 break;
501         }
502
503         //In this case, all directions are invalid because of lack of space.
504         if (idx == 4) {
505                 //TODO 1: Find the largest space direction.
506                 /*
507                  Evas_Coord length[4];
508
509                  length[ ELM_CTXPOPUP_ARROW_DOWN ] = pos.y - area_rect.y;
510                  length[ ELM_CTXPOPUP_ARROW_UP ] = ( area_rect.y + area_rect.h ) - pos.y;
511                  length[ ELM_CTXPOPUP_ARROW_RIGHT ] = pos.x - area_rect.x;
512                  length[ ELM_CTXPOPUP_ARROW_LEFT ] = ( area_rect.x + area_rect.w ) - pos.x;
513
514                  int i, j, idx;
515                  for( i = 0; i < 4; ++i ) {
516                  for( j = 1; j < 4; ++j ) {
517                  if( length[ idx ] < length[ j ] ) {
518                  idx = j;
519                  }
520                  }
521                  }
522                  */
523                 //TODO 1: Find the largest space direction.
524                 Evas_Coord length[2];
525                 length[0] = pos.y - area_rect.y;
526                 length[1] = (area_rect.y + area_rect.h) - pos.y;
527
528                 if (length[0] > length[1]) idx = ELM_CTXPOPUP_ARROW_DOWN;
529                 else idx = ELM_CTXPOPUP_ARROW_UP;
530
531                 //TODO 2: determine x , y
532                 switch (idx) {
533                         case ELM_CTXPOPUP_ARROW_DOWN:
534                                 _adjust_pos_x(&pos, &base_size, &area_rect);
535                                 pos.y -= (base_size.y + finger_size);
536                                 arrow = ELM_CTXPOPUP_ARROW_DOWN;
537                                 if (pos.y < area_rect.y + arrow_size.y) {
538                                         base_size.y -= ((area_rect.y + arrow_size.y) - pos.y);
539                                         pos.y = area_rect.y + arrow_size.y;
540                                 }
541                                 break;
542                         case ELM_CTXPOPUP_ARROW_RIGHT:
543                                 _adjust_pos_y(indicator_h, &pos, &base_size, &area_rect);
544                                 pos.x -= (base_size.x + finger_size);
545                                 arrow = ELM_CTXPOPUP_ARROW_RIGHT;
546                                 if (pos.x < area_rect.x + arrow_size.x) {
547                                         base_size.x -= ((area_rect.x + arrow_size.x) - pos.x);
548                                         pos.x = area_rect.x + arrow_size.x;
549                                 }
550                                 break;
551                         case ELM_CTXPOPUP_ARROW_LEFT:
552                                 _adjust_pos_y(indicator_h, &pos, &base_size, &area_rect);
553                                 pos.x += finger_size;
554                                 arrow = ELM_CTXPOPUP_ARROW_LEFT;
555                                 if (pos.x + arrow_size.x + base_size.x > area_rect.x + area_rect.w) {
556                                         base_size.x -= ((pos.x + arrow_size.x + base_size.x)
557                                                 - (area_rect.x + area_rect.w));
558                                 }
559                                 break;
560                         case ELM_CTXPOPUP_ARROW_UP:
561                                 _adjust_pos_x(&pos, &base_size, &area_rect);
562                                 pos.y += finger_size;
563                                 arrow = ELM_CTXPOPUP_ARROW_UP;
564                                 if (pos.y + arrow_size.y + base_size.y > area_rect.y + area_rect.h) {
565                                         base_size.y -= ((pos.y + arrow_size.y + base_size.y) - (area_rect.y + area_rect.h));
566                                 }
567                                 break;
568                         default:
569                                 break;
570                 }
571         }
572
573         //Final position and size. 
574         rect->x = pos.x;
575         rect->y = pos.y;
576         rect->w = base_size.x;
577         rect->h = base_size.y;
578
579         //resize scroller according to final size. 
580         if (!wd->content) {
581                 evas_object_geometry_get(wd->box, NULL, NULL, &temp.x, &temp.y);
582                 evas_object_size_hint_min_set(wd->scroller, temp.x + (base_size.x       - min_calc_w), temp.y + (base_size.y - min_calc_h));
583         }
584
585         return arrow;
586 }
587
588 static void _update_arrow_obj(Evas_Object *obj, Elm_Ctxpopup_Arrow arrow_dir) 
589 {
590         Evas_Coord x, y;
591         Evas_Coord_Rectangle arrow_size;
592         Evas_Coord_Rectangle area_rect;
593         Evas_Coord parent_w, parent_h;
594         Widget_Data *wd = elm_widget_data_get(obj);
595
596         if (!wd) return;
597
598         evas_object_geometry_get(obj, &x, &y, NULL, NULL);
599         evas_object_geometry_get(wd->arrow, NULL, NULL, &arrow_size.w,
600                         &arrow_size.h);
601
602         switch (arrow_dir) {
603                 case ELM_CTXPOPUP_ARROW_LEFT: {
604                         edje_object_signal_emit(wd->arrow, "elm,state,left", "elm");
605                         arrow_size.y = (y - (arrow_size.h * 0.5));
606                         arrow_size.x = (x + elm_finger_size_get());
607                         break;
608                 }
609                 case ELM_CTXPOPUP_ARROW_RIGHT: {
610                         edje_object_signal_emit(wd->arrow, "elm,state,right", "elm");
611                         arrow_size.y = (y - (arrow_size.h * 0.5));
612                         arrow_size.x = (x - elm_finger_size_get() - arrow_size.w);
613                         break;
614                 }
615                 case ELM_CTXPOPUP_ARROW_UP: {
616                         edje_object_signal_emit(wd->arrow, "elm,state,top", "elm");
617                         arrow_size.x = (x - (arrow_size.w * 0.5));
618                         arrow_size.y = (y + elm_finger_size_get());
619                         break;
620                 }
621                 case ELM_CTXPOPUP_ARROW_DOWN: {
622                         edje_object_signal_emit(wd->arrow, "elm,state,bottom", "elm");
623                         arrow_size.x = (x - (arrow_size.w * 0.5));
624                         arrow_size.y = (y - elm_finger_size_get() - arrow_size.h);
625                         break;
626                 }
627                 default:
628                         break;
629         }
630
631         //Adjust arrow position to prevent out of area
632         if (wd->area_rect) 
633                 evas_object_geometry_get(wd->area_rect, &area_rect.x, &area_rect.y,
634                                 &area_rect.w, &area_rect.h);
635         else {
636                 evas_object_geometry_get(wd->parent, NULL, NULL, &parent_w, &parent_h);
637                 area_rect.x = 0;
638                 area_rect.y = 0;
639                 area_rect.w = parent_w;
640                 area_rect.h = parent_h;
641         }
642
643         //TODO: Temporary Code. make it more flexible
644         if ((arrow_size.x - (arrow_size.w / 2)) < area_rect.x) 
645                 arrow_size.x = area_rect.x + (arrow_size.w / 2);
646         else if ((arrow_size.x + arrow_size.w) > (area_rect.x + area_rect.w)) 
647                 arrow_size.x = (area_rect.x + area_rect.w) - arrow_size.w
648                                 - (arrow_size.w / 2);
649 /*
650         //TODO: Temporary Code. make it more flexible
651         if ((arrow_size.y - (arrow_size.h / 2)) < area_rect.y) {
652                 arrow_size.y = arrow_size.y + (arrow_size.h / 2);
653         } else if ((arrow_size.y + arrow_size.h) > (area_rect.y + area_rect.h)) {
654                 arrow_size.y = (area_rect.y + area_rect.h) - arrow_size.h
655                                 - (arrow_size.h / 2);
656         }
657 */
658         evas_object_move(wd->arrow, arrow_size.x, arrow_size.y);
659 }
660
661 static void _sizing_eval(Evas_Object *obj) 
662 {
663         Widget_Data *wd;
664         Eina_List *elist;
665         Elm_Ctxpopup_Item *item;
666         Evas_Coord_Rectangle rect = { 0, 0, 1, 1 };
667         Evas_Coord_Point box_size = { 0, 0 };
668         Evas_Coord_Point _box_size = { 0, 0 };
669
670         wd = (Widget_Data *) elm_widget_data_get(obj);
671         if ((!wd) || (!wd->parent)) return;
672         int idx = 0;
673
674         //Box, scroller 
675         EINA_LIST_FOREACH(wd->items, elist, item)
676         {
677                 _item_sizing_eval(item);
678                 evas_object_size_hint_min_get(item->base, &_box_size.x, &_box_size.y);
679                 if(!wd->horizontal) {
680                         if(_box_size.x > box_size.x) box_size.x = _box_size.x;
681                         if(_box_size.y != -1 ) box_size.y += _box_size.y;
682                 } else {
683                         if(_box_size.x != -1 ) box_size.x += _box_size.x;
684                         if(_box_size.y > box_size.y) box_size.y = _box_size.y;
685                 }
686                 ++idx;
687         }
688
689         if(!wd->content) {
690                 evas_object_size_hint_min_set(wd->box, box_size.x, box_size.y);
691                 evas_object_size_hint_min_set(wd->scroller, box_size.x, box_size.y);
692         }
693
694         //Base
695         wd->arrow_dir = _calc_base_geometry(obj, &rect);
696         if ((!wd->position_forced) && (wd->arrow_dir != -1)) {
697                 _update_arrow_obj(obj, wd->arrow_dir);
698                 _shift_base_by_arrow(wd->arrow, wd->arrow_dir, &rect);
699         }
700
701         evas_object_move(wd->base, rect.x, rect.y);
702         evas_object_resize(wd->base, rect.w, rect.h);
703 }
704
705 static void _shift_base_by_arrow(Evas_Object *arrow,
706                 Elm_Ctxpopup_Arrow arrow_dir, Evas_Coord_Rectangle *rect) 
707 {
708         Evas_Coord arrow_w, arrow_h;
709         evas_object_geometry_get(arrow, NULL, NULL, &arrow_w, &arrow_h);
710
711         switch (arrow_dir) {
712         case ELM_CTXPOPUP_ARROW_LEFT:
713                 rect->x += arrow_w;
714                 break;
715         case ELM_CTXPOPUP_ARROW_RIGHT:
716                 rect->x -= arrow_w;
717                 break;
718         case ELM_CTXPOPUP_ARROW_UP:
719                 rect->y += arrow_h;
720                 break;
721         case ELM_CTXPOPUP_ARROW_DOWN:
722                 rect->y -= arrow_h;
723                 break;
724         default:
725                 break;
726         }
727 }
728
729 static void _del_pre_hook(Evas_Object *obj) {
730
731         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
732         if (!wd) return;
733
734         evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE,
735                         _parent_resize, obj);
736
737         if(wd->transit) {
738                 elm_transit_stop(wd->transit);
739                 elm_transit_del(wd->transit);
740                 wd->transit = NULL;
741         }
742
743         _delete_area_rect_callbacks(wd);
744
745 }
746
747 static void _del_hook(Evas_Object *obj) 
748 {
749         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
750
751         if (!wd) return;
752         elm_ctxpopup_clear(obj);
753         evas_object_del(wd->arrow);
754         evas_object_del(wd->base);
755
756         free(wd);
757 }
758
759 static void _theme_hook(Evas_Object *obj) 
760 {
761         Eina_List *elist;
762         Elm_Ctxpopup_Item *item;
763         char buf[256];
764
765         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
766
767         if (!wd) return;
768
769         //Items
770         EINA_LIST_FOREACH(wd->items, elist, item)
771         {
772                 if (item->separator)
773                 {
774                         _elm_theme_object_set(obj, item->base, "ctxpopup", "separator",
775                                         elm_widget_style_get(obj));
776                         if (wd->horizontal)
777                                 edje_object_signal_emit(item->base, "elm,state,horizontal",     "elm");
778                 }
779                 else
780                 {
781                         if (item->label && item->icon)
782                         {
783                                 _elm_theme_object_set(obj, item->base, "ctxpopup",
784                                                 "icon_text_style_item",
785                                                 elm_widget_style_get(obj));
786                         }
787                         else if (item->label)
788                         {
789                                 _elm_theme_object_set(obj, item->base, "ctxpopup",
790                                                 "text_style_item",
791                                                 elm_widget_style_get(obj));
792                         }
793                         else if (item->icon)
794                         {
795                                 _elm_theme_object_set(obj, item->base, "ctxpopup",
796                                                 "icon_style_item",
797                                                 elm_widget_style_get(obj));
798                         }
799                         if (item->label)
800                                 edje_object_part_text_set(item->base, "elm.text", item->label);
801
802                         if (item->disabled)
803                                 edje_object_signal_emit(item->base, "elm,state,disabled", "elm");
804                 }
805                 edje_object_message_signal_process(item->base);
806         }
807
808         //button layout
809         if (wd->btn_layout) {
810                 sprintf(buf, "buttons%d", wd->btn_cnt);
811                 _elm_theme_object_set(obj, wd->btn_layout, "ctxpopup", buf,
812                                 elm_widget_style_get(obj));
813         }
814
815         _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg", elm_widget_style_get(obj));
816         _elm_theme_object_set(obj, wd->base, "ctxpopup", "base", elm_widget_style_get(obj));
817         _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow",
818                         elm_widget_style_get(obj));
819
820         if (!strncmp(elm_object_style_get(obj), "default", strlen("default")
821                         * sizeof(char)))
822                 elm_object_style_set(wd->scroller, "ctxpopup");
823         else
824                 elm_object_style_set(wd->scroller, elm_object_style_get(obj));
825
826         if(wd->visible) {
827                 _reset_scroller_size(wd);
828                 _sizing_eval(obj);
829         }
830 }
831
832 static void _bg_clicked_cb(void *data, Evas_Object *obj, const char *emission,
833                 const char *source) 
834 {
835         evas_object_hide(data);
836 }
837
838 static void _parent_resize(void *data, Evas *e, Evas_Object *obj,
839                 void *event_info) 
840 {
841         Evas_Coord w, h;
842
843         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(data);
844         if (!wd)        return;
845
846         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
847         evas_object_resize(wd->bg, w, h);
848
849    if(wd->visible == EINA_FALSE) return;
850         wd->visible = EINA_FALSE;
851    _hide_ctxpopup(data);
852
853 }
854
855 static void _ctxpopup_show(void *data, Evas *e, Evas_Object *obj,
856                 void *event_info) 
857 {
858         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
859         if(wd == NULL) return;
860
861         if ((eina_list_count(wd->items) < 1) && (!wd->content) && (wd->btn_cnt < 1))
862                 return;
863
864         wd->visible = EINA_TRUE;
865         _sizing_eval(obj);
866
867         if (!wd->screen_dimmed_disabled) {
868                 evas_object_show(wd->bg);
869                 edje_object_signal_emit(wd->bg, "elm,state,show", "elm");
870         }
871
872         evas_object_show(wd->base);
873
874         if (!wd->position_forced) {
875                 evas_object_show(wd->arrow);
876         }
877
878         _show_effect(wd);
879 }
880
881 static void _hide_ctxpopup(Evas_Object *obj)
882 {
883         //TODO: Consider implementing effect in edc.
884         Widget_Data *wd = elm_widget_data_get(obj);
885
886         if (!wd->screen_dimmed_disabled)
887                 evas_object_hide(wd->bg);
888
889         if(!wd->position_forced)
890                 evas_object_hide(wd->arrow);
891
892         evas_object_hide(wd->base);
893
894         _reset_scroller_size(wd);
895         evas_object_smart_callback_call(obj, "hide", NULL);
896 }
897
898 static void _ctxpopup_hide(void *data, Evas *e, Evas_Object *obj, void *event_info) 
899 {
900         Widget_Data *wd = (Widget_Data*) elm_widget_data_get(obj);
901         if(wd == NULL) return;
902
903         if(wd->visible == EINA_FALSE)    return;
904
905         wd->visible = EINA_FALSE;
906
907         if (!wd->screen_dimmed_disabled)
908                 edje_object_signal_emit(wd->bg, "elm,state,hide", "elm");
909
910         _hide_effect(obj);
911 }
912
913 static void _ctxpopup_scroller_resize(void *data, Evas *e, Evas_Object * obj,
914                 void *event_info) 
915 {
916         Widget_Data *wd;
917         Evas_Coord w, h;
918
919         wd = elm_widget_data_get(data);
920         if(wd == NULL) return;
921
922         if(!wd->visible) return;
923         if(wd->finished) return;
924
925         evas_object_geometry_get(wd->scroller, 0, 0, &w, &h);
926
927         if( w != 0 && h !=0 ) {
928                 if((w <= wd->max_sc_w) && (h <= wd->max_sc_h) ) {
929                         _sizing_eval(data);
930                         wd->finished = EINA_TRUE;
931                         return ;
932                 }
933         }
934
935         if(wd->max_sc_w < w )   wd->max_sc_w = w;
936         if(wd->max_sc_h < h ) wd->max_sc_h = h;
937
938         _sizing_eval(data);
939 }
940
941 static void _ctxpopup_move(void *data, Evas *e, Evas_Object *obj,
942                 void *event_info) 
943 {
944         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
945         if(wd == NULL) return;
946
947         if (wd->visible && !wd->position_forced)
948                 evas_object_show(wd->arrow);
949
950         _reset_scroller_size(wd);
951         _sizing_eval(obj);
952 }
953
954 static void _ctxpopup_item_select(void *data, Evas_Object *obj,
955                 const char *emission, const char *source) 
956 {
957         Elm_Ctxpopup_Item *item = (Elm_Ctxpopup_Item *) data;
958
959         if (!item) return;
960         if (item->disabled) return;
961         if (item->func) 
962                 item->func(item->data, item->ctxpopup, item);
963         _ctxpopup_hide(item->ctxpopup, NULL, item->ctxpopup, NULL);
964 }
965
966 static void _item_obj_create(Elm_Ctxpopup_Item *item, char *group_name) 
967 {
968         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(item->ctxpopup);
969
970         if (!wd) return;
971         item->base = edje_object_add(evas_object_evas_get(wd->base));
972         _elm_theme_object_set(item->ctxpopup, item->base, "ctxpopup", group_name,
973                         elm_widget_style_get(item->ctxpopup));
974         edje_object_signal_callback_add(item->base, "elm,action,click", "",
975                         _ctxpopup_item_select, item);
976         evas_object_size_hint_align_set(item->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
977         evas_object_size_hint_weight_set(item->base, EVAS_HINT_EXPAND,
978                         EVAS_HINT_EXPAND);
979         evas_object_show(item->base);
980 }
981
982 static void _content_changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info)
983 {
984         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
985         if(!wd) return;
986
987         if(wd->visible) _sizing_eval(data);
988 }
989
990 static void _content_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
991 {
992         elm_ctxpopup_content_unset(data, obj);
993 }
994
995
996
997 /**
998  * Get the icon object for the given item.
999  *
1000  * @param[in] item      Ctxpopup item
1001  * @return              Icon object or NULL if the item does not have icon
1002  *
1003  * @ingroup Ctxpopup
1004  */
1005 EAPI Evas_Object *
1006 elm_ctxpopup_item_icon_get(Elm_Ctxpopup_Item *item) 
1007 {
1008         if (!item) return NULL;
1009         return item->icon;
1010 }
1011
1012 /**
1013  * Disable or Enable the scroller for contextual popup.
1014  *
1015  * @param[in] obj               Ctxpopup object
1016  * @param[in] disabled  disable or enable
1017  *
1018  * @ingroup Ctxpopup
1019  */
1020 EAPI void elm_ctxpopup_scroller_disabled_set(Evas_Object *obj,
1021                 Eina_Bool disabled) 
1022 {
1023         ELM_CHECK_WIDTYPE(obj, widtype);
1024         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1025
1026         if (!wd)        return;
1027         if (wd->scroller_disabled == disabled)  return;
1028
1029         if (disabled)
1030                 elm_object_scroll_freeze_push(wd->scroller);
1031         else
1032                 elm_object_scroll_freeze_pop(wd->scroller);
1033
1034         wd->scroller_disabled = disabled;
1035 }
1036
1037 /**
1038  * Get the label for the given item.
1039  *
1040  * @param[in] item              Ctxpopup item
1041  * @return              Label or NULL if the item does not have label
1042  *
1043  * @ingroup Ctxpopup
1044  *
1045  */
1046 EAPI const char *
1047 elm_ctxpopup_item_label_get(Elm_Ctxpopup_Item *item) 
1048 {
1049         if (!item) return NULL;
1050         return item->label;
1051 }
1052
1053 /**
1054  * Add a new ctxpopup object to the parent.
1055  *
1056  * @param[in] parent    window object
1057  * @return              New object or NULL if it cannot be created
1058  *
1059  * @ingroup Ctxpopup
1060  */
1061 EAPI Evas_Object *
1062 elm_ctxpopup_add(Evas_Object *parent) 
1063 {
1064         Evas_Object *obj;
1065         Evas *e;
1066         Widget_Data *wd;
1067         Evas_Coord x, y, w, h;
1068
1069         wd = ELM_NEW(Widget_Data);
1070         e = evas_object_evas_get(parent);
1071
1072         if (!e)
1073                 return NULL;
1074
1075         obj = elm_widget_add(e);
1076         ELM_SET_WIDTYPE(widtype, "ctxpopup");
1077         elm_widget_type_set(obj, "ctxpopup");
1078         elm_widget_sub_object_add(parent, obj);
1079         elm_widget_data_set(obj, wd);
1080         elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1081         elm_widget_del_hook_set(obj, _del_hook);
1082         elm_widget_theme_hook_set(obj, _theme_hook);
1083
1084         wd->parent = parent;
1085
1086         //Background
1087         wd->bg = edje_object_add(e);
1088         elm_widget_sub_object_add(obj, wd->bg);
1089         _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg", "default");
1090         evas_object_geometry_get(parent, &x, &y, &w, &h);
1091         evas_object_move(wd->bg, x, y);
1092         evas_object_resize(wd->bg, w, h);
1093         edje_object_signal_callback_add(wd->bg, "elm,action,click", "",
1094                         _bg_clicked_cb, obj);
1095
1096         //Base
1097         wd->base = edje_object_add(e);
1098         elm_widget_sub_object_add(obj, wd->base);
1099         _elm_theme_object_set(obj, wd->base, "ctxpopup", "base", "default");
1100
1101         //Scroller
1102         wd->scroller = elm_scroller_add(obj);
1103         elm_object_style_set(wd->scroller, "ctxpopup");
1104         evas_object_size_hint_align_set(wd->scroller, EVAS_HINT_FILL,
1105                         EVAS_HINT_FILL);
1106         elm_scroller_bounce_set(wd->scroller, EINA_FALSE, EINA_TRUE);
1107         evas_object_event_callback_add(wd->scroller, EVAS_CALLBACK_RESIZE,
1108                         _ctxpopup_scroller_resize, obj);
1109
1110         //Box
1111         wd->box = elm_box_add(obj);
1112         evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
1113                         EVAS_HINT_EXPAND);
1114         elm_scroller_content_set(wd->scroller, wd->box);
1115
1116         edje_object_part_swallow(wd->base, "elm.swallow.scroller", wd->scroller);
1117
1118         //Arrow
1119         wd->arrow = edje_object_add(e);
1120         elm_widget_sub_object_add(obj, wd->arrow);
1121         _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow", "default");
1122
1123         wd->arrow_priority[0] = ELM_CTXPOPUP_ARROW_DOWN;
1124         wd->arrow_priority[1] = ELM_CTXPOPUP_ARROW_RIGHT;
1125         wd->arrow_priority[2] = ELM_CTXPOPUP_ARROW_LEFT;
1126         wd->arrow_priority[3] = ELM_CTXPOPUP_ARROW_UP;
1127
1128         evas_object_event_callback_add(parent, EVAS_CALLBACK_RESIZE,
1129                         _parent_resize, obj);
1130         evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _ctxpopup_show, NULL);
1131         evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _ctxpopup_hide, NULL);
1132         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _ctxpopup_move, NULL);
1133         evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _ctxpopup_changed_size_hints, NULL);
1134         
1135         return obj;
1136 }
1137
1138 /**
1139  * Clear all items in given ctxpopup object.
1140  *
1141  * @param[in] obj               Ctxpopup object
1142  *
1143  * @ingroup Ctxpopup
1144  */
1145 EAPI void elm_ctxpopup_clear(Evas_Object *obj) 
1146 {
1147         ELM_CHECK_WIDTYPE(obj, widtype);
1148         Eina_List *elist;
1149         Elm_Ctxpopup_Item *item;
1150
1151         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1152
1153         if (!wd) return;
1154
1155         EINA_LIST_FOREACH(wd->items, elist, item)
1156         {
1157                 if (item->label)
1158                 eina_stringshare_del(item->label);
1159                 if (item->icon)
1160                 evas_object_del(item->icon);
1161                 wd->items = eina_list_remove(wd->items, item);
1162                 free(item);
1163         }
1164
1165         evas_object_hide(wd->arrow);
1166         evas_object_hide(wd->base);
1167 }
1168
1169 /**
1170  * Change the mode to horizontal or vertical.
1171  *
1172  * @param[in] obj       Ctxpopup object
1173  * @param horizontal    EINA_TRUE - horizontal mode, EINA_FALSE - vertical mode
1174  *
1175  * @ingroup Ctxpopup
1176  */
1177 EAPI void elm_ctxpopup_horizontal_set(Evas_Object *obj, Eina_Bool horizontal) 
1178 {
1179         ELM_CHECK_WIDTYPE(obj, widtype);
1180         Eina_List *elist;
1181         Elm_Ctxpopup_Item *item;
1182         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1183
1184         if (!wd) return;
1185
1186         if (wd->horizontal == horizontal) return;
1187         wd->horizontal = horizontal;
1188         if (!horizontal) {
1189                 elm_box_horizontal_set(wd->box, EINA_FALSE);
1190                 elm_scroller_bounce_set(wd->scroller, EINA_FALSE, EINA_TRUE);
1191                 EINA_LIST_FOREACH       (wd->items, elist, item)
1192                 edje_object_signal_emit(item->base, "elm,state,vertical", "elm");
1193         }
1194         else
1195         {
1196                 elm_box_horizontal_set(wd->box, EINA_TRUE);
1197                 elm_scroller_bounce_set(wd->scroller, EINA_TRUE, EINA_FALSE);
1198                 EINA_LIST_FOREACH(wd->items, elist, item)
1199                 edje_object_signal_emit(item->base, "elm,state,horizontal", "elm");
1200         }       
1201 }
1202
1203 /**
1204  * Get the value of current horizontal mode.
1205  *
1206  * @param[in] obj               Ctxpopup object
1207  * @return              EINA_TRUE - horizontal mode, EINA_FALSE - vertical mode.
1208  *
1209  * @ingroup Ctxpopup
1210  */
1211 EAPI Eina_Bool elm_ctxpopup_horizontal_get(Evas_Object *obj) 
1212 {
1213         ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1214         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1215         if (!wd) return EINA_FALSE;
1216         return wd->horizontal;
1217 }
1218
1219 /**
1220  * reset the icon on the given item. 
1221  *
1222  * @param[in] item              Ctxpopup item
1223  * @param[in] icon              Icon object to be set
1224  *
1225  * @ingroup Ctxpopup
1226  */
1227 EAPI void elm_ctxpopup_item_icon_set(Elm_Ctxpopup_Item *item, Evas_Object *icon) 
1228 {
1229         Widget_Data *wd;
1230
1231         if (!item) return;
1232         wd = (Widget_Data *) elm_widget_data_get(item->ctxpopup);
1233         if (!wd) return;
1234         if (item->icon == icon) return;
1235         if (item->icon) {
1236                 elm_widget_sub_object_del(item->base, item->icon);
1237                 evas_object_del(item->icon);
1238         }
1239         item->icon = icon;
1240         edje_object_part_swallow(item->base, "elm.swallow.icon", item->icon);
1241         edje_object_message_signal_process(item->base);
1242
1243         if (wd->visible) {
1244                 _reset_scroller_size(wd);
1245                 _sizing_eval(item->ctxpopup);
1246         }
1247 }
1248
1249 /**
1250  * reset the label on the given item. 
1251  *
1252  * @param[in] item              Ctxpopup item
1253  * @param[in] label             Label to be set
1254  * 
1255  * @ingroup Ctxpopup
1256  */
1257 EAPI void elm_ctxpopup_item_label_set(Elm_Ctxpopup_Item *item,
1258                 const char *label) 
1259 {
1260         Widget_Data *wd;
1261
1262         if (!item)
1263                 return;
1264
1265         if (item->label) {
1266                 eina_stringshare_del(item->label);
1267                 item->label = NULL;
1268         }
1269
1270         item->label = eina_stringshare_add(label);
1271         edje_object_message_signal_process(item->base);
1272         edje_object_part_text_set(item->base, "elm.text", label);
1273
1274         wd = elm_widget_data_get(item->ctxpopup);
1275         if (!wd)
1276                 return;
1277
1278         if (wd->visible) {
1279                 _reset_scroller_size(wd);
1280                 _sizing_eval(item->ctxpopup);
1281         }
1282 }
1283
1284 /**
1285  * Add a new item in given ctxpopup object.
1286  *
1287  * @param[in] obj               Ctxpopup object
1288  * @param[in] icon              Icon to be set
1289  * @param[in] label   Label to be set
1290  * @param[in] func              Callback function to call when this item click is clicked
1291  * @param[in] data    User data for callback function
1292  * @return              Added ctxpopup item
1293  * 
1294  * @ingroup Ctxpopup
1295  */
1296 EAPI Elm_Ctxpopup_Item *
1297 elm_ctxpopup_item_add(Evas_Object *obj, Evas_Object *icon, const char *label,
1298                 Evas_Smart_Cb func, void *data) 
1299 {
1300         ELM_CHECK_WIDTYPE(obj, widtype)NULL;
1301         Elm_Ctxpopup_Item *item;
1302         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1303
1304         if (!wd)
1305                 return NULL;
1306
1307         _separator_obj_add(obj);
1308
1309         item = ELM_NEW(Elm_Ctxpopup_Item);
1310         if (!item)
1311                 return NULL;
1312
1313         item->func = func;
1314         item->data = data;
1315         item->ctxpopup = obj;
1316         item->separator = EINA_FALSE;
1317
1318         if (icon && label)
1319                 _item_obj_create(item, "icon_text_style_item");
1320         else if (icon)
1321                 _item_obj_create(item, "icon_style_item");
1322         else
1323                 _item_obj_create(item, "text_style_item");
1324
1325         wd->items = eina_list_append(wd->items, item);
1326         elm_box_pack_end(wd->box, item->base);
1327         elm_ctxpopup_item_icon_set(item, icon);
1328         elm_ctxpopup_item_label_set(item, label);
1329
1330         return item;
1331 }
1332
1333 /**
1334  * Delete the given item in ctxpopup object.
1335  *
1336  * @param item[in]  Ctxpopup item to be deleted
1337  *
1338  * @ingroup Ctxpopup
1339  */
1340 EAPI void elm_ctxpopup_item_del(Elm_Ctxpopup_Item *item) 
1341 {
1342         Widget_Data *wd;
1343         Evas_Object *obj;
1344
1345         if (!item)
1346                 return;
1347
1348         obj = item->ctxpopup;
1349
1350         if (item->label)
1351                 eina_stringshare_del(item->label);
1352         if (item->icon)
1353                 evas_object_del(item->icon);
1354         if (item->base)
1355                 evas_object_del(item->base);
1356
1357         wd = (Widget_Data *) elm_widget_data_get(item->ctxpopup);
1358         if (wd) {
1359                 _separator_obj_del(wd, item);
1360                 wd->items = eina_list_remove(wd->items, item);
1361         }
1362         free(item);
1363         if (eina_list_count(wd->items) == 0) {
1364                 _ctxpopup_hide(obj, NULL, obj, NULL);
1365         }
1366 }
1367
1368 /**
1369  * Disable or Enable the given item. Once an item is disabled, the click event will be never happend for the item.
1370  *
1371  * @param[in] item              Ctxpopup item to be disabled
1372  * @param[in] disabled  EINA_TRUE - disable, EINA_FALSE - enable
1373  *
1374  * @ingroup Ctxpopup
1375  */
1376 EAPI void elm_ctxpopup_item_disabled_set(Elm_Ctxpopup_Item *item,
1377                 Eina_Bool disabled) 
1378 {
1379         Widget_Data *wd;
1380
1381         if (!item) return;
1382         if (disabled == item->disabled) return;
1383
1384         wd = (Widget_Data *) elm_widget_data_get(item->ctxpopup);
1385         
1386         if (disabled)
1387                 edje_object_signal_emit(item->base, "elm,state,disabled", "elm");
1388         else
1389                 edje_object_signal_emit(item->base, "elm,state,enabled", "elm");
1390
1391         edje_object_message_signal_process(item->base);
1392         item->disabled = disabled;
1393 }
1394
1395 /**
1396  * Disable or Enable background dimmed function 
1397  * @param[in] obj               Ctxpopup object
1398  * @param[in] dimmed    EINA_TRUE - disable, EINA_FALSE - enable
1399  *
1400  * @ingroup Ctxpopup
1401  */
1402 EAPI void elm_ctxpopup_screen_dimmed_disabled_set(Evas_Object *obj,
1403                 Eina_Bool disabled) 
1404 {
1405         ELM_CHECK_WIDTYPE(obj, widtype);
1406         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1407
1408         if (!wd)
1409                 return;
1410
1411         wd->screen_dimmed_disabled = disabled;
1412
1413         if (wd->visible) {
1414                 if (!disabled) {
1415                         evas_object_show(wd->bg);
1416                 }
1417         }
1418 }
1419
1420 /**
1421  * Append additional button in ctxpoppup bottom layout.
1422  * @param[in] obj               Ctxpopup object
1423  * @param[in] label  Button label
1424  * @param[in] func   Button clicked event callback function
1425  * @param[in] data   Button clicked event callback function data
1426  *
1427  * @ingroup Ctxpopup
1428  */
1429 EAPI void elm_ctxpopup_button_append(Evas_Object *obj, const char *label,
1430                 Evas_Smart_Cb func, const void *data) 
1431 {
1432         ELM_CHECK_WIDTYPE(obj, widtype);
1433         char buf[256];
1434         Evas_Object *btn;
1435         Evas_Coord w, h;
1436         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1437
1438         if (!wd) return;
1439         if (!wd->btn_layout) _btn_layout_create(obj);
1440
1441         ++wd->btn_cnt;
1442         sprintf(buf, "buttons%d", wd->btn_cnt);
1443         _elm_theme_object_set(obj, wd->btn_layout, "ctxpopup", buf,
1444                         elm_widget_style_get(obj));
1445
1446         btn = elm_button_add(obj);
1447         elm_object_style_set(btn, "text_only/style1");
1448         elm_button_label_set(btn, label);
1449         evas_object_smart_callback_add(btn, "clicked", func, data);
1450         sprintf(buf, "actionbtn%d", wd->btn_cnt);
1451         edje_object_part_swallow(wd->btn_layout, buf, btn);
1452
1453         edje_object_part_geometry_get(wd->btn_layout, buf, NULL, NULL, &w, &h);
1454         evas_object_size_hint_max_set(wd->btn_layout, -1, h);
1455
1456         if (wd->visible) {
1457                 _reset_scroller_size(wd);
1458                 _sizing_eval(obj);
1459         }
1460 }
1461
1462 /**
1463  * Set the priority of arrow direction
1464  *
1465  *  This functions gives user to set the priority of ctxpopup box showing position.
1466  *
1467  * @param[in] obj               Ctxpopup object
1468  * @param[in] first    1st priority of arrow direction
1469  * @param[in] second 2nd priority of arrow direction
1470  * @param[in] third   3th priority of arrow direction
1471  * @param[in] fourth 4th priority of arrow direction
1472  *
1473  * @ingroup Ctxpopup
1474  */
1475 EAPI void elm_ctxpopup_arrow_priority_set(Evas_Object *obj,
1476                 Elm_Ctxpopup_Arrow first, Elm_Ctxpopup_Arrow second,
1477                 Elm_Ctxpopup_Arrow third, Elm_Ctxpopup_Arrow fourth) 
1478 {
1479         ELM_CHECK_WIDTYPE(obj, widtype);
1480         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1481
1482         if (!wd)
1483                 return;
1484         wd->arrow_priority[0] = first;
1485         wd->arrow_priority[1] = second;
1486         wd->arrow_priority[2] = third;
1487         wd->arrow_priority[3] = fourth;
1488 }
1489
1490
1491
1492 /**
1493  * Swallow the user content
1494  *
1495  * @param[in] obj               Ctxpopup object
1496  * @param[in] content   Content to be swallowed
1497  *
1498  * @ingroup Ctxpopup
1499  */
1500 EAPI void elm_ctxpopup_content_set(Evas_Object *obj, Evas_Object *content) 
1501 {
1502         ELM_CHECK_WIDTYPE(obj, widtype);
1503         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1504         Evas_Coord w, h;
1505
1506         if(!wd || !content) return;
1507
1508         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _content_del, obj);
1509         evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _ctxpopup_changed_size_hints, NULL);
1510         
1511         edje_object_part_swallow(wd->base, "elm.swallow.content", content);
1512         elm_widget_sub_object_add(obj, content);
1513         edje_object_signal_emit(wd->base, "elm,state,content,enable", "elm");
1514         elm_ctxpopup_scroller_disabled_set(obj, EINA_TRUE);
1515
1516         wd->content = content;
1517
1518         if(wd->visible) _sizing_eval(obj);
1519 }
1520
1521 /**
1522  * Unswallow the user content
1523  *
1524  * @param[in] obj               Ctxpopup object
1525  * @return              The unswallowed content
1526  *
1527  * @ingroup Ctxpopup
1528  */
1529 EAPI Evas_Object *
1530 elm_ctxpopup_content_unset(Evas_Object *obj) 
1531 {
1532         ELM_CHECK_WIDTYPE(obj, widtype)NULL;
1533         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1534         Evas_Object *content;
1535
1536         content = wd->content;
1537         wd->content = NULL;
1538
1539         if (content) edje_object_part_unswallow(wd->base, content);
1540
1541         elm_widget_sub_object_del(obj, content);
1542         edje_object_signal_emit(wd->base, "elm,state,content,disable", "elm");
1543
1544         elm_ctxpopup_scroller_disabled_set(obj, EINA_FALSE);
1545
1546         if (wd->visible)
1547                 _sizing_eval(obj);
1548
1549         return content;
1550 }
1551
1552 /**
1553  * Change the origin of the ctxpopup position.
1554  *
1555  * Basically, ctxpopup position is computed internally. When user call evas_object_move,
1556  * Ctxpopup will be showed up with that position which is indicates the arrow point.
1557  *
1558  * @param[in] obj               Ctxpopup object
1559  * @param[in] forced    EINA_TRUE is left-top. EINA_FALSE is indicates arrow point.
1560  *
1561  * @ingroup Ctxpopup
1562  */
1563 EAPI void elm_ctxpopup_position_forced_set(Evas_Object *obj, Eina_Bool forced) 
1564 {
1565         ELM_CHECK_WIDTYPE(obj, widtype);
1566         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1567
1568         wd->position_forced = forced;
1569
1570         if (forced) evas_object_hide(wd->arrow);
1571
1572         if (wd->visible) {
1573                 _reset_scroller_size(wd);
1574                 _sizing_eval(obj);
1575         }
1576 }
1577
1578 /**
1579  * Get the status of the position forced
1580  *
1581  * @param[in] obj               Ctxpopup objet
1582  * @return                      value of position forced
1583  *
1584  * @ingroup Ctxpopup
1585  */
1586 EAPI Eina_Bool elm_ctxpopup_position_forced_get(Evas_Object *obj) 
1587 {
1588         ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1589         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1590
1591         return wd->position_forced;
1592 }
1593
1594 EAPI Elm_Ctxpopup_Item *
1595 elm_ctxpopup_icon_add(Evas_Object *obj, Evas_Object *icon, Evas_Smart_Cb func,
1596                 void *data) 
1597 {
1598         return elm_ctxpopup_item_add(obj, icon, NULL, func, data);
1599 }
1600
1601 EAPI Elm_Ctxpopup_Item *
1602 elm_ctxpopup_label_add(Evas_Object *obj, const char *label, Evas_Smart_Cb func,
1603                 void *data) 
1604 {
1605         return elm_ctxpopup_item_add(obj, NULL, label, func, data);
1606 }
1607
1608 /**
1609  * Set the area of ctxpopup will show up. Ctxpopup will not be out of this area. 
1610  * The responsibility of the area object is to user.
1611  *
1612  * @param[in] obj               Ctxpopup objet
1613  * @param[in] area              area object
1614  *
1615  * @ingroup Ctxpopup
1616  */
1617 EAPI void elm_ctxpopup_area_set(Evas_Object *obj, Evas_Object *area) 
1618 {
1619         ELM_CHECK_WIDTYPE(obj, widtype);
1620         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1621
1622         _delete_area_rect_callbacks(wd);
1623
1624         if (area) {
1625                 evas_object_event_callback_add(area, EVAS_CALLBACK_DEL, _area_rect_del,
1626                                 obj);
1627                 evas_object_event_callback_add(area, EVAS_CALLBACK_MOVE,
1628                                 _area_rect_move, obj);
1629                 evas_object_event_callback_add(area, EVAS_CALLBACK_RESIZE,
1630                                 _area_rect_resize, obj);
1631                 wd->area_rect = area;
1632         }
1633
1634 }
1635
1636 EAPI void elm_ctxpopup_title_set(Evas_Object *obj, const char *title )
1637 {
1638         ELM_CHECK_WIDTYPE(obj, widtype);
1639         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1640         if(!wd) return;
1641         if(!title) return;
1642
1643         if(wd->title) eina_stringshare_del(wd->title);
1644         wd->title = eina_stringshare_add(title);
1645         edje_object_part_text_set(wd->base, "elm.title", title);
1646         
1647 }
1648
1649 EAPI const char* elm_ctxpopup_title_get(Evas_Object *obj)
1650 {
1651         ELM_CHECK_WIDTYPE(obj, widtype);
1652         Widget_Data *wd = (Widget_Data *) elm_widget_data_get(obj);
1653         return wd->title; 
1654 }
1655         
1656