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