1 #include <Elementary.h>
3 #include "elm_widget_ctxpopup.h"
5 #define OUTLINE_TEXT "Contextual popup is opened, double tap to close the popup"
7 EAPI const char ELM_CTXPOPUP_SMART_NAME[] = "elm_ctxpopup";
9 static const char ACCESS_OUTLINE_PART[] = "access.outline";
11 static const char SIG_DISMISSED[] = "dismissed";
12 static const char SIG_LANG_CHANGED[] = "language,changed";
13 static const char SIG_ACCESS_CHANGED[] = "access,changed";
15 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
17 {SIG_LANG_CHANGED, ""},
18 {SIG_ACCESS_CHANGED, ""},
22 EVAS_SMART_SUBCLASS_NEW
23 (ELM_CTXPOPUP_SMART_NAME, _elm_ctxpopup, Elm_Ctxpopup_Smart_Class,
24 Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
27 _elm_ctxpopup_smart_translate(Evas_Object *obj)
29 ELM_CTXPOPUP_DATA_GET(obj, sd);
30 Elm_Ctxpopup_Item *it;
33 evas_object_hide(obj);
35 EINA_LIST_FOREACH(sd->items, l, it)
36 elm_widget_item_translate(it);
42 _access_object_get(const Evas_Object *obj, const char* part)
45 ELM_CTXPOPUP_DATA_GET(obj, sd);
47 po = (Evas_Object *)edje_object_part_object_get(ELM_WIDGET_DATA(sd)->resize_obj, part);
48 ao = evas_object_data_get(po, "_part_access_obj");
54 _elm_ctxpopup_smart_focus_next(const Evas_Object *obj,
55 Elm_Focus_Direction dir,
58 Eina_List *items = NULL;
61 ELM_CTXPOPUP_DATA_GET(obj, sd);
66 if (_elm_config->access_mode)
68 ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
69 if (ao) items = eina_list_append(items, ao);
71 /* scroller exists when ctxpopup has an item */
73 items = eina_list_append(items, sd->scr);
75 items = eina_list_append(items, sd->box);
77 return elm_widget_focus_list_next_get
78 (obj, items, eina_list_data_get, dir, next);
82 if (!elm_widget_focus_next_get(sd->box, dir, next))
84 elm_widget_focused_object_clear(sd->box);
85 elm_widget_focus_next_get(sd->box, dir, next);
89 return elm_widget_focus_list_next_get
90 (obj, items, eina_list_data_get, dir, next);
95 _elm_ctxpopup_smart_focus_direction(const Evas_Object *obj,
96 const Evas_Object *base,
98 Evas_Object **direction,
103 void *(*list_data_get)(const Eina_List *list);
105 ELM_CTXPOPUP_DATA_GET(obj, sd);
110 list_data_get = eina_list_data_get;
112 l = eina_list_append(l, sd->box);
113 ret = elm_widget_focus_list_direction_get
114 (obj, base, l, list_data_get, degree, direction, weight);
121 _freeze_on_cb(void *data __UNUSED__,
123 void *event_info __UNUSED__)
125 ELM_CTXPOPUP_DATA_GET(obj, sd);
127 if ((!sd) || (!sd->scr)) return;
128 elm_object_scroll_freeze_push(sd->scr);
132 _freeze_off_cb(void *data __UNUSED__,
134 void *event_info __UNUSED__)
136 ELM_CTXPOPUP_DATA_GET(obj, sd);
138 if ((!sd) || (!sd->scr)) return;
139 elm_object_scroll_freeze_pop(sd->scr);
143 _hold_on_cb(void *data __UNUSED__,
145 void *event_info __UNUSED__)
147 ELM_CTXPOPUP_DATA_GET(obj, sd);
149 if ((!sd) || (!sd->scr)) return;
150 elm_object_scroll_hold_push(sd->scr);
154 _hold_off_cb(void *data __UNUSED__,
156 void *event_info __UNUSED__)
158 ELM_CTXPOPUP_DATA_GET(obj, sd);
160 if ((!sd) || (!sd->scr)) return;
161 elm_object_scroll_hold_pop(sd->scr);
165 _x_pos_adjust(Evas_Coord_Point *pos,
166 Evas_Coord_Point *base_size,
167 Evas_Coord_Rectangle *hover_area)
169 pos->x -= (base_size->x / 2);
171 if (pos->x < hover_area->x)
172 pos->x = hover_area->x;
173 else if ((pos->x + base_size->x) > (hover_area->x + hover_area->w))
174 pos->x = (hover_area->x + hover_area->w) - base_size->x;
176 if (base_size->x > hover_area->w)
177 base_size->x -= (base_size->x - hover_area->w);
179 if (pos->x < hover_area->x)
180 pos->x = hover_area->x;
184 _y_pos_adjust(Evas_Coord_Point *pos,
185 Evas_Coord_Point *base_size,
186 Evas_Coord_Rectangle *hover_area)
188 pos->y -= (base_size->y / 2);
190 if (pos->y < hover_area->y)
191 pos->y = hover_area->y;
192 else if ((pos->y + base_size->y) > (hover_area->y + hover_area->h))
193 pos->y = hover_area->y + hover_area->h - base_size->y;
195 if (base_size->y > hover_area->h)
196 base_size->y -= (base_size->y - hover_area->h);
198 if (pos->y < hover_area->y)
199 pos->y = hover_area->y;
203 _item_select_cb(void *data,
204 Evas_Object *obj __UNUSED__,
205 void *event_info __UNUSED__)
207 Elm_Ctxpopup_Item *item = data;
210 if (elm_widget_item_disabled_get(item)) return;
213 item->func((void*)item->base.data, WIDGET(item), data);
217 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
219 Elm_Ctxpopup_Item *it = (Elm_Ctxpopup_Item *)data;
220 const char *txt = NULL;
221 Evas_Object *icon = NULL;
223 if (!it) return NULL;
228 if (txt) return strdup(txt);
229 if (icon) return strdup(E_("icon"));
234 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
236 Elm_Ctxpopup_Item *it = (Elm_Ctxpopup_Item *)data;
237 if (!it) return NULL;
239 if (it->base.disabled)
240 return strdup(E_("State: Disabled"));
246 _access_type_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
248 return strdup(E_("Contextual Popup"));
252 _access_activate_cb(void *data __UNUSED__,
253 Evas_Object *part_obj __UNUSED__,
254 Elm_Object_Item *item)
256 _item_select_cb(item, NULL, NULL);
260 _access_focusable_button_register(Evas_Object *obj, Elm_Ctxpopup_Item *it)
264 ai = _elm_access_object_get(obj);
266 _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
267 _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, it);
268 _elm_access_callback_set(ai, ELM_ACCESS_TYPE, _access_type_cb, NULL);
269 _elm_access_activate_callback_set(ai, _access_activate_cb, it);
271 ((Elm_Widget_Item *)it)->access_obj = obj;
275 _item_new(Elm_Ctxpopup_Item *item,
278 ELM_CTXPOPUP_DATA_GET(WIDGET(item), sd);
281 VIEW(item) = edje_object_add(evas_object_evas_get(sd->box));
282 edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
283 _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", group_name,
284 elm_widget_style_get(WIDGET(item)));
285 evas_object_size_hint_align_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
286 evas_object_show(VIEW(item));
290 _item_icon_set(Elm_Ctxpopup_Item *item,
294 evas_object_del(item->icon);
299 edje_object_part_swallow(VIEW(item), "elm.swallow.icon", item->icon);
300 edje_object_message_signal_process(VIEW(item));
304 _item_label_set(Elm_Ctxpopup_Item *item,
307 if (!eina_stringshare_replace(&item->label, label))
310 edje_object_part_text_set(VIEW(item), "elm.text", label);
311 edje_object_message_signal_process(VIEW(item));
315 _item_in_focusable_button(Elm_Ctxpopup_Item *item)
319 bt = elm_button_add(WIDGET(item));
320 elm_object_style_set(bt, "focus");
321 evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
322 elm_object_part_content_set(bt, "elm.swallow.content", VIEW(item));
323 evas_object_smart_callback_add(bt, "clicked", _item_select_cb, item);
324 evas_object_show(bt);
330 _item_del_pre_hook(Elm_Object_Item *it)
332 Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
334 ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
335 if (!sd) return EINA_FALSE;
337 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
339 if (ctxpopup_it->icon)
340 evas_object_del(ctxpopup_it->icon);
341 if (VIEW(ctxpopup_it))
342 evas_object_del(VIEW(ctxpopup_it));
344 eina_stringshare_del(ctxpopup_it->label);
345 sd->items = eina_list_remove(sd->items, ctxpopup_it);
347 if (eina_list_count(sd->items) < 1)
349 evas_object_hide(WIDGET(ctxpopup_it));
352 if (sd->visible) elm_layout_sizing_eval(WIDGET(ctxpopup_it));
358 _items_remove(Elm_Ctxpopup_Smart_Data *sd)
361 Elm_Ctxpopup_Item *item;
363 if (!sd->items) return;
365 EINA_LIST_FOREACH(sd->items, elist, item)
366 elm_widget_item_del(item);
372 _scroller_size_reset(Elm_Ctxpopup_Smart_Data *sd)
374 sd->finished = EINA_FALSE;
380 _item_sizing_eval(Elm_Ctxpopup_Item *item)
382 Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
386 edje_object_size_min_restricted_calc(VIEW(item), &min_w, &min_h, min_w,
388 evas_object_size_hint_min_set(VIEW(item), min_w, min_h);
389 evas_object_size_hint_max_set(VIEW(item), max_w, max_h);
392 static Elm_Ctxpopup_Direction
393 _base_geometry_calc(Evas_Object *obj,
394 Evas_Coord_Rectangle *rect)
396 Elm_Ctxpopup_Direction dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
397 Evas_Coord_Rectangle hover_area;
398 Evas_Coord_Point pos = {0, 0};
399 Evas_Coord_Point arrow_size;
400 Evas_Coord_Point base_size;
401 Evas_Coord_Point max_size;
402 Evas_Coord_Point min_size;
403 Evas_Coord_Point temp;
406 ELM_CTXPOPUP_DATA_GET(obj, sd);
408 if (!rect) return ELM_CTXPOPUP_DIRECTION_DOWN;
410 edje_object_part_geometry_get
411 (sd->arrow, "ctxpopup_arrow", NULL, NULL, &arrow_size.x, &arrow_size.y);
412 evas_object_resize(sd->arrow, arrow_size.x, arrow_size.y);
414 //Initialize Area Rectangle.
415 evas_object_geometry_get
416 (sd->parent, &hover_area.x, &hover_area.y, &hover_area.w,
419 evas_object_geometry_get(obj, &pos.x, &pos.y, NULL, NULL);
422 edje_object_size_min_calc
423 (ELM_WIDGET_DATA(sd)->resize_obj, &base_size.x, &base_size.y);
424 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
427 evas_object_size_hint_max_get(obj, &max_size.x, &max_size.y);
428 if ((max_size.x == -1) || (max_size.y == -1))
429 edje_object_size_max_get(sd->layout, &max_size.x, &max_size.y);
431 if ((max_size.y > 0) && (base_size.y > max_size.y))
432 base_size.y = max_size.y;
434 if ((max_size.x > 0) && (base_size.x > max_size.x))
435 base_size.x = max_size.x;
438 evas_object_size_hint_min_get(obj, &min_size.x, &min_size.y);
439 if ((min_size.x == 0) || (min_size.y == 0))
440 edje_object_size_min_get(sd->layout, &min_size.x, &min_size.y);
442 if ((min_size.y > 0) && (base_size.y < min_size.y))
443 base_size.y = min_size.y;
445 if ((min_size.x > 0) && (base_size.x < min_size.x))
446 base_size.x = min_size.x;
448 //Check the Which direction is available.
449 //If find a avaialble direction, it adjusts position and size.
450 for (idx = 0; idx < 4; idx++)
452 switch (sd->dir_priority[idx])
454 case ELM_CTXPOPUP_DIRECTION_UNKNOWN:
456 case ELM_CTXPOPUP_DIRECTION_UP:
457 temp.y = (pos.y - base_size.y);
458 if ((temp.y - arrow_size.y) < hover_area.y)
461 _x_pos_adjust(&pos, &base_size, &hover_area);
462 pos.y -= base_size.y;
463 dir = ELM_CTXPOPUP_DIRECTION_UP;
466 case ELM_CTXPOPUP_DIRECTION_LEFT:
467 temp.x = (pos.x - base_size.x);
468 if ((temp.x - arrow_size.x) < hover_area.x)
471 _y_pos_adjust(&pos, &base_size, &hover_area);
472 pos.x -= base_size.x;
473 dir = ELM_CTXPOPUP_DIRECTION_LEFT;
476 case ELM_CTXPOPUP_DIRECTION_RIGHT:
477 temp.x = (pos.x + base_size.x);
478 if ((temp.x + arrow_size.x) >
479 (hover_area.x + hover_area.w))
482 _y_pos_adjust(&pos, &base_size, &hover_area);
483 dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
486 case ELM_CTXPOPUP_DIRECTION_DOWN:
487 temp.y = (pos.y + base_size.y);
488 if ((temp.y + arrow_size.y) >
489 (hover_area.y + hover_area.h))
492 _x_pos_adjust(&pos, &base_size, &hover_area);
493 dir = ELM_CTXPOPUP_DIRECTION_DOWN;
502 //In this case, all directions are invalid because of lack of space.
505 Evas_Coord length[2];
509 length[0] = pos.y - hover_area.y;
510 length[1] = (hover_area.y + hover_area.h) - pos.y;
512 // ELM_CTXPOPUP_DIRECTION_UP
513 if (length[0] > length[1])
515 _x_pos_adjust(&pos, &base_size, &hover_area);
516 pos.y -= base_size.y;
517 dir = ELM_CTXPOPUP_DIRECTION_UP;
518 if (pos.y < (hover_area.y + arrow_size.y))
520 base_size.y -= ((hover_area.y + arrow_size.y) - pos.y);
521 pos.y = hover_area.y + arrow_size.y;
524 //ELM_CTXPOPUP_DIRECTION_DOWN
527 _x_pos_adjust(&pos, &base_size, &hover_area);
528 dir = ELM_CTXPOPUP_DIRECTION_DOWN;
529 if ((pos.y + arrow_size.y + base_size.y) >
530 (hover_area.y + hover_area.h))
532 ((pos.y + arrow_size.y + base_size.y) -
533 (hover_area.y + hover_area.h));
538 length[0] = pos.x - hover_area.x;
539 length[1] = (hover_area.x + hover_area.w) - pos.x;
541 //ELM_CTXPOPUP_DIRECTION_LEFT
542 if (length[0] > length[1])
544 _y_pos_adjust(&pos, &base_size, &hover_area);
545 pos.x -= base_size.x;
546 dir = ELM_CTXPOPUP_DIRECTION_LEFT;
547 if (pos.x < (hover_area.x + arrow_size.x))
549 base_size.x -= ((hover_area.x + arrow_size.x) - pos.x);
550 pos.x = hover_area.x + arrow_size.x;
553 //ELM_CTXPOPUP_DIRECTION_RIGHT
556 _y_pos_adjust(&pos, &base_size, &hover_area);
557 dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
558 if (pos.x + (arrow_size.x + base_size.x) >
559 hover_area.x + hover_area.w)
561 ((pos.x + arrow_size.x + base_size.x) -
562 (hover_area.x + hover_area.w));
567 //Final position and size.
570 rect->w = base_size.x;
571 rect->h = base_size.y;
577 _arrow_update(Evas_Object *obj,
578 Elm_Ctxpopup_Direction dir,
579 Evas_Coord_Rectangle base_size)
581 Evas_Coord_Rectangle arrow_size;
584 Evas_Coord_Rectangle shadow_left_top, shadow_right_bottom, arrow_padding;
586 ELM_CTXPOPUP_DATA_GET(obj, sd);
588 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
589 evas_object_geometry_get
590 (sd->arrow, NULL, NULL, &arrow_size.w, &arrow_size.h);
592 /* tizen only : since ctxpopup of tizen has shadow, start and end padding of arrow, it should be put together when updating arrow
593 * so there are some differences between open source and tizen */
594 edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_left_top_padding", NULL, NULL, &shadow_left_top.w, &shadow_left_top.h);
595 edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_right_bottom_padding", NULL, NULL, &shadow_right_bottom.w, &shadow_right_bottom.h);
596 edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "ctxpopup_frame_left_top", NULL, NULL, &arrow_padding.w, &arrow_padding.h);
598 /* arrow is not being kept as sub-object on purpose, here. the
599 * design of the widget does not help with the contrary */
603 case ELM_CTXPOPUP_DIRECTION_RIGHT:
604 edje_object_signal_emit(sd->arrow, "elm,state,left", "elm");
605 edje_object_part_swallow
606 (ELM_WIDGET_DATA(sd)->resize_obj,
607 (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
608 "elm.swallow.arrow_left"), sd->arrow);
612 if (y <= ((arrow_size.h * 0.5) + base_size.y + shadow_left_top.h + arrow_padding.h))
614 else if (y >= (base_size.y + base_size.h - ((arrow_size.h * 0.5) + shadow_right_bottom.h + arrow_padding.h)))
615 y = base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2));
617 y = y - base_size.y - ((arrow_size.h * 0.5) + shadow_left_top.h + arrow_padding.h);
618 drag = (double)(y) / (double)(base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2)));
619 edje_object_part_drag_value_set
620 (ELM_WIDGET_DATA(sd)->resize_obj,
621 (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
622 "elm.swallow.arrow_left"), 1, drag);
626 case ELM_CTXPOPUP_DIRECTION_LEFT:
627 edje_object_signal_emit(sd->arrow, "elm,state,right", "elm");
628 edje_object_part_swallow
629 (ELM_WIDGET_DATA(sd)->resize_obj,
630 (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
631 "elm.swallow.arrow_right"), sd->arrow);
635 if (y <= ((arrow_size.h * 0.5) + base_size.y + shadow_left_top.h + arrow_padding.h))
637 else if (y >= (base_size.y + base_size.h - ((arrow_size.h * 0.5) + shadow_right_bottom.h + arrow_padding.h)))
638 y = base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2));
640 y = y - base_size.y - ((arrow_size.h * 0.5) + shadow_left_top.h + arrow_padding.h);
641 drag = (double)(y) / (double)(base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2)));
642 edje_object_part_drag_value_set
643 (ELM_WIDGET_DATA(sd)->resize_obj,
644 (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
645 "elm.swallow.arrow_right"), 0, drag);
649 case ELM_CTXPOPUP_DIRECTION_DOWN:
650 edje_object_signal_emit(sd->arrow, "elm,state,top", "elm");
651 edje_object_part_swallow
652 (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_up",
657 if (x <= ((arrow_size.w * 0.5) + base_size.x + shadow_left_top.w + arrow_padding.w))
659 else if (x >= (base_size.x + base_size.w - ((arrow_size.w * 0.5) + shadow_right_bottom.w + arrow_padding.w)))
660 x = base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2));
662 x = x - base_size.x - ((arrow_size.w * 0.5) + shadow_left_top.w + arrow_padding.w);
663 drag = (double)(x) / (double)(base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2)));
664 edje_object_part_drag_value_set
665 (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_up",
670 case ELM_CTXPOPUP_DIRECTION_UP:
671 edje_object_signal_emit(sd->arrow, "elm,state,bottom", "elm");
672 edje_object_part_swallow
673 (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_down",
678 if (x <= ((arrow_size.w * 0.5) + base_size.x + shadow_left_top.w + arrow_padding.w))
680 else if (x >= (base_size.x + base_size.w - ((arrow_size.w * 0.5) + shadow_right_bottom.w + arrow_padding.w)))
681 x = base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2));
683 x = x - base_size.x - ((arrow_size.w * 0.5) + shadow_left_top.w + arrow_padding.w);
684 drag = (double)(x) / (double)(base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2)));
685 edje_object_part_drag_value_set
686 (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_down",
695 //should be here for getting accurate geometry value
696 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
700 _show_signals_emit(Evas_Object *obj,
701 Elm_Ctxpopup_Direction dir)
703 ELM_CTXPOPUP_DATA_GET(obj, sd);
705 if (!sd->visible) return;
709 case ELM_CTXPOPUP_DIRECTION_UP:
710 edje_object_signal_emit(sd->layout, "elm,state,show,up", "elm");
713 case ELM_CTXPOPUP_DIRECTION_LEFT:
714 edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,show,right" :
715 "elm,state,show,left"), "elm");
718 case ELM_CTXPOPUP_DIRECTION_RIGHT:
719 edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,show,left" :
720 "elm,state,show,right"), "elm");
723 case ELM_CTXPOPUP_DIRECTION_DOWN:
724 edje_object_signal_emit(sd->layout, "elm,state,show,down", "elm");
731 edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
735 _hide_signals_emit(Evas_Object *obj,
736 Elm_Ctxpopup_Direction dir)
738 ELM_CTXPOPUP_DATA_GET(obj, sd);
740 if (!sd->visible) return;
744 case ELM_CTXPOPUP_DIRECTION_UP:
745 edje_object_signal_emit(sd->layout, "elm,state,hide,up", "elm");
748 case ELM_CTXPOPUP_DIRECTION_LEFT:
749 edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,hide,right" :
750 "elm,state,hide,left"), "elm");
753 case ELM_CTXPOPUP_DIRECTION_RIGHT:
754 edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,hide,left" :
755 "elm,state,hide,right"), "elm");
758 case ELM_CTXPOPUP_DIRECTION_DOWN:
759 edje_object_signal_emit(sd->layout, "elm,state,hide,down", "elm");
766 edje_object_signal_emit(sd->bg, "elm,state,hide", "elm");
770 _base_shift_by_arrow(Evas_Object *arrow,
771 Elm_Ctxpopup_Direction dir,
772 Evas_Coord_Rectangle *rect)
774 Evas_Coord arrow_w, arrow_h;
776 evas_object_geometry_get(arrow, NULL, NULL, &arrow_w, &arrow_h);
780 case ELM_CTXPOPUP_DIRECTION_RIGHT:
784 case ELM_CTXPOPUP_DIRECTION_LEFT:
788 case ELM_CTXPOPUP_DIRECTION_DOWN:
792 case ELM_CTXPOPUP_DIRECTION_UP:
802 _elm_ctxpopup_smart_sub_object_add(Evas_Object *obj,
805 Elm_Widget_Smart_Class *parent_parent;
807 parent_parent = (Elm_Widget_Smart_Class *)((Evas_Smart_Class *)
808 _elm_ctxpopup_parent_sc)->parent;
810 /* skipping layout's code, which registers size hint changing
811 * callback on sub objects. a hack to make ctxpopup live, as it is,
812 * on the new classing schema. this widget needs a total
814 if (!parent_parent->sub_object_add(obj, sobj))
821 _elm_ctxpopup_smart_sizing_eval(Evas_Object *obj)
824 Elm_Ctxpopup_Item *item;
825 Evas_Coord_Rectangle rect = { 0, 0, 1, 1 };
826 Evas_Coord_Point box_size = { 0, 0 };
827 Evas_Coord_Point _box_size = { 0, 0 };
831 ELM_CTXPOPUP_DATA_GET(obj, sd);
834 EINA_LIST_FOREACH(sd->items, elist, item)
836 _item_sizing_eval(item);
837 evas_object_size_hint_min_get(VIEW(item), &_box_size.x, &_box_size.y);
839 str = edje_object_data_get(VIEW(item), "item_max_size");
843 maxw = maxw * elm_widget_scale_get(obj) * elm_config_scale_get();
845 if (_box_size.x > maxw)
847 edje_object_signal_emit(VIEW(item), "elm,state,text,ellipsis", "elm");
848 edje_object_message_signal_process(VIEW(item));
854 if (_box_size.x > box_size.x)
855 box_size.x = _box_size.x;
856 if (_box_size.y != -1)
857 box_size.y += _box_size.y;
861 if (_box_size.x != -1)
862 box_size.x += _box_size.x;
863 if (_box_size.y > box_size.y)
864 box_size.y = _box_size.y;
868 // if (!sd->arrow) return; /* simple way to flag "under deletion" */
870 if ((!sd->content) && (sd->scr))
872 evas_object_size_hint_min_set(sd->box, box_size.x, box_size.y);
873 elm_scroller_content_min_limit(sd->scr, EINA_TRUE, EINA_TRUE);
874 evas_object_size_hint_min_set(sd->scr, box_size.x, box_size.y);
878 sd->dir = _base_geometry_calc(obj, &rect);
882 _arrow_update(obj, sd->dir, rect);
883 _base_shift_by_arrow(sd->arrow, sd->dir, &rect);
885 //resize scroller according to final size
886 if ((!sd->content) && (sd->scr))
888 elm_scroller_content_min_limit(sd->scr, EINA_FALSE, EINA_FALSE);
889 evas_object_smart_calculate(sd->scr);
892 evas_object_size_hint_min_set(ELM_WIDGET_DATA(sd)->resize_obj, rect.w, rect.h);
893 evas_object_resize(ELM_WIDGET_DATA(sd)->resize_obj, rect.w, rect.h);
895 evas_object_move(sd->layout, rect.x, rect.y);
896 evas_object_resize(sd->layout, rect.w, rect.h);
898 _show_signals_emit(obj, sd->dir);
902 _on_parent_del(void *data,
904 Evas_Object *obj __UNUSED__,
905 void *event_info __UNUSED__)
907 evas_object_del(data);
911 _on_parent_move(void *data,
913 Evas_Object *obj __UNUSED__,
914 void *event_info __UNUSED__)
916 ELM_CTXPOPUP_DATA_GET(data, sd);
919 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
923 _scroller_size_reset(sd);
924 elm_layout_sizing_eval(data);
929 _on_parent_resize(void *data,
931 Evas_Object *obj __UNUSED__,
932 void *event_info __UNUSED__)
934 ELM_CTXPOPUP_DATA_GET(data, sd);
936 _hide_signals_emit(data, sd->dir);
938 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
940 evas_object_hide(data);
941 evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
945 _parent_detach(Evas_Object *obj)
947 ELM_CTXPOPUP_DATA_GET(obj, sd);
949 if (!sd->parent) return;
951 evas_object_event_callback_del_full
952 (sd->parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
953 evas_object_event_callback_del_full
954 (sd->parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
955 evas_object_event_callback_del_full
956 (sd->parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
960 _on_content_resized(void *data,
962 Evas_Object *obj __UNUSED__,
963 void *event_info __UNUSED__)
965 ELM_CTXPOPUP_DATA_GET(data, sd);
967 elm_box_recalculate(sd->box);
968 elm_layout_sizing_eval(data);
972 _access_outline_activate_cb(void *data,
973 Evas_Object *part_obj __UNUSED__,
974 Elm_Object_Item *item __UNUSED__)
976 evas_object_hide(data);
977 evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
981 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
984 ELM_CTXPOPUP_DATA_GET(obj, sd);
988 ao = _elm_access_edje_object_part_object_register
989 (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_OUTLINE_PART);
990 _elm_access_text_set(_elm_access_object_get(ao),
991 ELM_ACCESS_TYPE, E_(OUTLINE_TEXT));
992 _elm_access_activate_callback_set
993 (_elm_access_object_get(ao), _access_outline_activate_cb, obj);
997 _elm_access_edje_object_part_object_unregister
998 (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_OUTLINE_PART);
1003 _elm_ctxpopup_smart_event(Evas_Object *obj,
1004 Evas_Object *src __UNUSED__,
1005 Evas_Callback_Type type,
1008 Evas_Event_Key_Down *ev = event_info;
1010 ELM_CTXPOPUP_DATA_GET(obj, sd);
1012 if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1013 if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1014 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
1016 if (!strcmp(ev->keyname, "Tab"))
1018 if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
1019 elm_widget_focus_cycle(sd->box, ELM_FOCUS_PREVIOUS);
1021 elm_widget_focus_cycle(sd->box, ELM_FOCUS_NEXT);
1025 if (((!strcmp(ev->keyname, "Left")) ||
1026 (!strcmp(ev->keyname, "KP_Left")) ||
1027 (!strcmp(ev->keyname, "Right")) ||
1028 (!strcmp(ev->keyname, "KP_Right")) ||
1029 (!strcmp(ev->keyname, "Up")) ||
1030 (!strcmp(ev->keyname, "KP_Up")) ||
1031 (!strcmp(ev->keyname, "Down")) ||
1032 (!strcmp(ev->keyname, "KP_Down"))) && (!ev->string))
1034 double degree = 0.0;
1036 if ((!strcmp(ev->keyname, "Left")) ||
1037 (!strcmp(ev->keyname, "KP_Left")))
1039 else if ((!strcmp(ev->keyname, "Right")) ||
1040 (!strcmp(ev->keyname, "KP_Right")))
1042 else if ((!strcmp(ev->keyname, "Up")) ||
1043 (!strcmp(ev->keyname, "KP_Up")))
1045 else if ((!strcmp(ev->keyname, "Down")) ||
1046 (!strcmp(ev->keyname, "KP_Down")))
1049 elm_widget_focus_direction_go(sd->box, degree);
1050 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1054 // TIZEN ONLY : 20130530 : ctxpopup will be dismissed by user
1055 //if (strcmp(ev->keyname, "Escape")) return EINA_FALSE;
1059 _hide_signals_emit(obj, sd->dir);
1061 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1066 //FIXME: lost the content size when theme hook is called.
1068 _elm_ctxpopup_smart_theme(Evas_Object *obj)
1071 Elm_Ctxpopup_Item *item;
1072 int idx = 0, orientation = -1;
1075 ELM_CTXPOPUP_DATA_GET(obj, sd);
1077 if (!ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->theme(obj))
1080 rtl = elm_widget_mirrored_get(obj);
1082 elm_widget_theme_object_set
1083 (obj, sd->bg, "ctxpopup", "bg", elm_widget_style_get(obj));
1085 if (edje_object_part_exists(elm_layout_edje_get(obj), "elm.swallow.arrow_up") ||
1086 edje_object_part_exists(elm_layout_edje_get(obj), "elm.swallow.arrow_down") ||
1087 edje_object_part_exists(elm_layout_edje_get(obj), "elm.swallow.arrow_left") ||
1088 edje_object_part_exists(elm_layout_edje_get(obj), "elm.swallow.arrow_right"))
1090 elm_widget_theme_object_set
1091 (obj, sd->arrow, "ctxpopup", "arrow", elm_widget_style_get(obj));
1095 evas_object_del(sd->arrow);
1099 orientation = sd->orientation;
1100 if (orientation == 90 || orientation == 270)
1101 elm_widget_theme_object_set
1102 (obj, sd->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(obj));
1104 elm_widget_theme_object_set
1105 (obj, sd->layout, "ctxpopup", "layout", elm_widget_style_get(obj));
1108 EINA_LIST_FOREACH(sd->items, elist, item)
1110 edje_object_mirrored_set(VIEW(item), rtl);
1112 if (item->label && item->icon)
1113 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1114 "icon_text_style_item",
1115 elm_widget_style_get(obj));
1116 else if (item->label)
1119 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1121 elm_widget_style_get(obj));
1123 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1124 "text_style_item_horizontal",
1125 elm_widget_style_get(obj));
1127 else if (item->icon)
1128 _elm_theme_object_set
1129 (obj, VIEW(item), "ctxpopup", "icon_style_item",
1130 elm_widget_style_get(obj));
1132 edje_object_part_text_set(VIEW(item), "elm.text", item->label);
1134 if (elm_widget_item_disabled_get(item))
1135 edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
1138 * For separator, if the first item has visible separator,
1139 * then it should be aligned with edge of the base part.
1140 * In some cases, it gives improper display. Ex) rounded corner
1141 * So the first item separator should be invisible.
1144 edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
1146 edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
1148 edje_object_message_signal_process(VIEW(item));
1151 if (evas_object_visible_get(sd->bg))
1152 edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
1156 if (!strncmp(elm_object_style_get(obj), "default", strlen("default")))
1157 elm_object_style_set(sd->scr, "ctxpopup");
1159 elm_object_style_set(sd->scr, elm_object_style_get(obj));
1162 elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
1164 elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
1167 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1171 _scroller_size_reset(sd);
1172 _elm_ctxpopup_smart_sizing_eval(obj);
1176 if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
1181 /* kind of a big and tricky override here: an internal box will hold
1182 * the actual content. content aliases won't be of much help here */
1184 _elm_ctxpopup_smart_content_set(Evas_Object *obj,
1186 Evas_Object *content)
1188 Evas_Coord min_w = -1, min_h = -1;
1190 ELM_CTXPOPUP_DATA_GET(obj, sd);
1192 if ((part) && (strcmp(part, "default")))
1193 return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_set
1194 (obj, part, content);
1196 if (!content) return EINA_FALSE;
1198 if (content == sd->content) return EINA_TRUE;
1200 if (sd->items) elm_ctxpopup_clear(obj);
1201 if (sd->content) evas_object_del(sd->content);
1206 sd->box = elm_box_add(obj);
1207 evas_object_size_hint_weight_set(sd->box, EVAS_HINT_EXPAND,
1209 evas_object_event_callback_add
1210 (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1211 ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_set
1212 (obj, "elm.swallow.content", sd->box);
1215 evas_object_size_hint_weight_set
1216 (content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1217 evas_object_size_hint_fill_set
1218 (content, EVAS_HINT_FILL, EVAS_HINT_FILL);
1220 /* since it's going to be a box content, not a layout's... */
1221 evas_object_show(content);
1223 evas_object_size_hint_min_get(content, &min_w, &min_h);
1224 evas_object_size_hint_min_set(sd->box, min_w, min_h);
1225 elm_box_pack_end(sd->box, content);
1227 sd->content = content;
1228 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1230 if (sd->visible) elm_layout_sizing_eval(obj);
1235 static Evas_Object *
1236 _elm_ctxpopup_smart_content_get(const Evas_Object *obj,
1239 ELM_CTXPOPUP_DATA_GET(obj, sd);
1241 if ((part) && (strcmp(part, "default")))
1242 return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_get
1248 static Evas_Object *
1249 _elm_ctxpopup_smart_content_unset(Evas_Object *obj,
1252 Evas_Object *content;
1254 ELM_CTXPOPUP_DATA_GET(obj, sd);
1256 if ((part) && (strcmp(part, "default")))
1257 return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_unset
1260 content = sd->content;
1261 if (!content) return NULL;
1263 evas_object_del(sd->box);
1266 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1268 if (sd->visible) elm_layout_sizing_eval(obj);
1274 _item_text_set_hook(Elm_Object_Item *it,
1278 Elm_Ctxpopup_Item *ctxpopup_it;
1280 if ((part) && (strcmp(part, "default"))) return;
1282 ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1284 _item_label_set(ctxpopup_it, label);
1288 _item_text_get_hook(const Elm_Object_Item *it,
1291 Elm_Ctxpopup_Item *ctxpopup_it;
1293 if (part && strcmp(part, "default")) return NULL;
1295 ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1296 return ctxpopup_it->label;
1300 _item_content_set_hook(Elm_Object_Item *it,
1302 Evas_Object *content)
1304 Elm_Ctxpopup_Item *ctxpopup_it;
1306 if ((part) && (strcmp(part, "icon"))) return;
1308 ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1310 ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
1312 _item_icon_set(ctxpopup_it, content);
1313 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1317 _scroller_size_reset(sd);
1318 _elm_ctxpopup_smart_sizing_eval(WIDGET(ctxpopup_it));
1322 static Evas_Object *
1323 _item_content_get_hook(const Elm_Object_Item *it,
1326 Elm_Ctxpopup_Item *ctxpopup_it;
1328 if (part && strcmp(part, "icon")) return NULL;
1330 ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1331 return ctxpopup_it->icon;
1335 _item_disable_hook(Elm_Object_Item *it)
1337 Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1339 ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
1342 if (elm_widget_item_disabled_get(it))
1343 edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,disabled", "elm");
1345 edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,enabled", "elm");
1349 _item_signal_emit_hook(Elm_Object_Item *it,
1350 const char *emission,
1353 Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1355 edje_object_signal_emit(VIEW(ctxpopup_it), emission, source);
1359 _bg_clicked_cb(void *data,
1360 Evas_Object *obj __UNUSED__,
1361 const char *emission __UNUSED__,
1362 const char *source __UNUSED__)
1364 ELM_CTXPOPUP_DATA_GET(data, sd);
1366 _hide_signals_emit(data, sd->dir);
1370 _on_show(void *data __UNUSED__,
1373 void *event_info __UNUSED__)
1376 Elm_Ctxpopup_Item *item;
1379 ELM_CTXPOPUP_DATA_GET(obj, sd);
1380 ELM_WIDGET_DATA_GET(obj, wsd);
1382 if ((!sd->items) && (!sd->content)) return;
1384 sd->visible = EINA_TRUE;
1386 evas_object_show(sd->bg);
1388 evas_object_show(sd->arrow);
1389 evas_object_show(sd->layout);
1391 edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
1392 elm_layout_signal_emit(obj, "elm,state,show", "elm");
1394 if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1395 elm_widget_theme_object_set
1396 (obj, sd->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(obj));
1398 elm_widget_theme_object_set
1399 (obj, sd->layout, "ctxpopup", "layout", elm_widget_style_get(obj));
1401 EINA_LIST_FOREACH(sd->items, elist, item)
1403 if (item->label && !item->icon)
1406 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1408 elm_widget_style_get(obj));
1410 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1411 "text_style_item_horizontal",
1412 elm_widget_style_get(obj));
1416 edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
1418 edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
1421 elm_layout_sizing_eval(obj);
1423 elm_object_focus_set(obj, EINA_TRUE);
1427 _on_hide(void *data __UNUSED__,
1430 void *event_info __UNUSED__)
1432 ELM_CTXPOPUP_DATA_GET(obj, sd);
1434 if (!sd->visible) return;
1436 evas_object_hide(sd->bg);
1438 evas_object_hide(sd->arrow);
1439 evas_object_hide(sd->layout);
1441 _scroller_size_reset(sd);
1443 sd->visible = EINA_FALSE;
1447 _on_move(void *data __UNUSED__,
1450 void *event_info __UNUSED__)
1452 ELM_CTXPOPUP_DATA_GET(obj, sd);
1454 if (sd->visible && sd->arrow) evas_object_show(sd->arrow);
1456 _scroller_size_reset(sd);
1457 _elm_ctxpopup_smart_sizing_eval(obj);
1461 _hide_finished_cb(void *data,
1462 Evas_Object *obj __UNUSED__,
1463 const char *emission __UNUSED__,
1464 const char *source __UNUSED__)
1466 evas_object_hide(data);
1467 evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
1471 _scroller_resize(void *data, Evas *e __UNUSED__,
1473 void *event_info __UNUSED__)
1477 ELM_CTXPOPUP_DATA_GET(data, sd);
1479 if (!sd->visible) return;
1480 if (sd->finished) return;
1482 evas_object_geometry_get(obj, 0, 0, &w, &h);
1484 if (w != 0 && h != 0)
1486 if ((w <= sd->max_sc_w) && (h <= sd->max_sc_h))
1488 _elm_ctxpopup_smart_sizing_eval(data);
1489 sd->finished = EINA_TRUE;
1494 if (sd->max_sc_w < w)
1496 if (sd->max_sc_h < h)
1499 _elm_ctxpopup_smart_sizing_eval(data);
1503 _ctxpopup_restack_cb(void *data __UNUSED__,
1506 void *event_info __UNUSED__)
1508 ELM_CTXPOPUP_DATA_GET(obj, sd);
1509 evas_object_stack_below(sd->bg, obj);
1510 evas_object_stack_below(sd->layout, obj);
1514 _list_del(Elm_Ctxpopup_Smart_Data *sd)
1516 if (!sd->scr) return;
1518 edje_object_part_unswallow(ELM_WIDGET_DATA(sd)->resize_obj, sd->scr);
1519 evas_object_del(sd->scr);
1521 evas_object_del(sd->box);
1526 _list_new(Evas_Object *obj)
1528 ELM_CTXPOPUP_DATA_GET(obj, sd);
1532 sd->scr = elm_scroller_add(obj);
1533 elm_object_style_set(sd->scr, "ctxpopup");
1534 evas_object_size_hint_align_set(sd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
1537 elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
1539 elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
1541 evas_object_event_callback_add(sd->scr, EVAS_CALLBACK_RESIZE,
1542 _scroller_resize, obj);
1543 edje_object_part_swallow(ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content", sd->scr);
1548 sd->box = elm_box_add(obj);
1549 evas_object_size_hint_weight_set(sd->box, EVAS_HINT_EXPAND,
1551 evas_object_event_callback_add
1552 (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1553 ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_set
1554 (obj, "elm.swallow.content", sd->box);
1557 elm_object_content_set(sd->scr, sd->box);
1558 elm_ctxpopup_horizontal_set(obj, sd->horizontal);
1562 _elm_ctxpopup_smart_disable(Evas_Object *obj)
1565 Elm_Object_Item *it;
1567 ELM_CTXPOPUP_DATA_GET(obj, sd);
1569 if (!ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->disable(obj))
1572 EINA_LIST_FOREACH(sd->items, l, it)
1573 elm_object_item_disabled_set(it, elm_widget_disabled_get(obj));
1579 _elm_ctxpopup_smart_add(Evas_Object *obj)
1581 EVAS_SMART_DATA_ALLOC(obj, Elm_Ctxpopup_Smart_Data);
1582 ELM_CTXPOPUP_DATA_GET(obj, sd);
1584 ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->base.add(obj);
1586 elm_layout_theme_set(obj, "ctxpopup", "base", elm_widget_style_get(obj));
1587 elm_layout_signal_callback_add
1588 (obj, "elm,action,hide,finished", "", _hide_finished_cb, obj);
1591 priv->bg = edje_object_add(evas_object_evas_get(obj));
1592 elm_widget_theme_object_set(obj, priv->bg, "ctxpopup", "bg", "default");
1593 edje_object_signal_callback_add
1594 (priv->bg, "elm,action,click", "", _bg_clicked_cb, obj);
1596 evas_object_stack_below(priv->bg, obj);
1599 priv->arrow = edje_object_add(evas_object_evas_get(obj));
1600 elm_widget_theme_object_set
1601 (obj, priv->arrow, "ctxpopup", "arrow", "default");
1603 priv->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1604 priv->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1605 priv->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1606 priv->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1607 priv->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1609 evas_object_event_callback_add
1610 (obj, EVAS_CALLBACK_RESTACK, _ctxpopup_restack_cb, obj);
1612 evas_object_smart_callback_add
1613 (obj, "scroll-freeze-on", _freeze_on_cb, obj);
1614 evas_object_smart_callback_add
1615 (obj, "scroll-freeze-off", _freeze_off_cb, obj);
1616 evas_object_smart_callback_add
1617 (obj, "scroll-hold-on", _hold_on_cb, obj);
1618 evas_object_smart_callback_add
1619 (obj, "scroll-hold-off", _hold_off_cb, obj);
1621 priv->box = elm_box_add(obj);
1622 evas_object_size_hint_weight_set
1623 (priv->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1625 evas_object_event_callback_add
1626 (priv->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1628 /* box will be our content placeholder, thus the parent's version call */
1629 ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_set
1630 (obj, "elm.swallow.content", priv->box);
1632 priv->layout = edje_object_add(evas_object_evas_get(obj));
1633 elm_widget_theme_object_set(obj, priv->layout, "ctxpopup", "layout", "default");
1635 edje_object_signal_callback_add
1636 (priv->layout, "elm,action,hide,finished", "", _hide_finished_cb, obj);
1637 edje_object_part_swallow(priv->layout, "swallow", ELM_WIDGET_DATA(sd)->resize_obj);
1638 evas_object_size_hint_weight_set
1639 (priv->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1641 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show, NULL);
1642 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide, NULL);
1643 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _on_move, NULL);
1645 elm_widget_can_focus_set(obj, EINA_TRUE);
1648 if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
1652 _elm_ctxpopup_smart_del(Evas_Object *obj)
1654 ELM_CTXPOPUP_DATA_GET(obj, sd);
1656 evas_object_event_callback_del_full
1657 (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1658 _parent_detach(obj);
1660 elm_ctxpopup_clear(obj);
1664 evas_object_del(sd->arrow);
1665 sd->arrow = NULL; /* stops _sizing_eval() from going on on deletion */
1668 evas_object_del(sd->bg);
1671 evas_object_del(sd->layout);
1674 ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->base.del(obj);
1678 _elm_ctxpopup_smart_parent_set(Evas_Object *obj,
1679 Evas_Object *parent)
1681 //default parent is to be hover parent
1682 elm_ctxpopup_hover_parent_set(obj, parent);
1686 _elm_ctxpopup_smart_access(Evas_Object *obj, Eina_Bool is_access)
1688 ELM_CTXPOPUP_CHECK(obj);
1690 _access_obj_process(obj, is_access);
1692 evas_object_smart_callback_call(obj, SIG_ACCESS_CHANGED, NULL);
1696 _elm_ctxpopup_smart_set_user(Elm_Ctxpopup_Smart_Class *sc)
1698 ELM_WIDGET_CLASS(sc)->base.add = _elm_ctxpopup_smart_add;
1699 ELM_WIDGET_CLASS(sc)->base.del = _elm_ctxpopup_smart_del;
1701 ELM_WIDGET_CLASS(sc)->parent_set = _elm_ctxpopup_smart_parent_set;
1702 ELM_WIDGET_CLASS(sc)->disable = _elm_ctxpopup_smart_disable;
1703 ELM_WIDGET_CLASS(sc)->event = _elm_ctxpopup_smart_event;
1704 ELM_WIDGET_CLASS(sc)->theme = _elm_ctxpopup_smart_theme;
1705 ELM_WIDGET_CLASS(sc)->translate = _elm_ctxpopup_smart_translate;
1706 ELM_WIDGET_CLASS(sc)->sub_object_add = _elm_ctxpopup_smart_sub_object_add;
1707 ELM_WIDGET_CLASS(sc)->focus_next = _elm_ctxpopup_smart_focus_next;
1708 ELM_WIDGET_CLASS(sc)->focus_direction = _elm_ctxpopup_smart_focus_direction;
1710 ELM_CONTAINER_CLASS(sc)->content_get = _elm_ctxpopup_smart_content_get;
1711 ELM_CONTAINER_CLASS(sc)->content_set = _elm_ctxpopup_smart_content_set;
1712 ELM_CONTAINER_CLASS(sc)->content_unset = _elm_ctxpopup_smart_content_unset;
1714 ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_ctxpopup_smart_sizing_eval;
1716 ELM_WIDGET_CLASS(sc)->access = _elm_ctxpopup_smart_access;
1719 EAPI const Elm_Ctxpopup_Smart_Class *
1720 elm_ctxpopup_smart_class_get(void)
1722 static Elm_Ctxpopup_Smart_Class _sc =
1723 ELM_CTXPOPUP_SMART_CLASS_INIT_NAME_VERSION(ELM_CTXPOPUP_SMART_NAME);
1724 static const Elm_Ctxpopup_Smart_Class *class = NULL;
1725 Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1730 _elm_ctxpopup_smart_set(&_sc);
1731 esc->callbacks = _smart_callbacks;
1738 elm_ctxpopup_add(Evas_Object *parent)
1742 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1744 obj = elm_widget_add(_elm_ctxpopup_smart_class_new(), parent);
1745 if (!obj) return NULL;
1747 if (!elm_widget_sub_object_add(parent, obj))
1748 ERR("could not add %p as sub object of %p", obj, parent);
1750 /* access: parent could be any object such as elm_list which does
1751 not know elc_ctxpopup as its child object in the focus_next(); */
1752 ELM_WIDGET_DATA_GET(obj, sd);
1753 ELM_CTXPOPUP_DATA_GET(obj, sd1);
1755 sd->highlight_root = EINA_TRUE;
1756 sd1->orientation = sd->orient_mode;
1758 _elm_widget_orient_signal_emit(obj);
1760 if (sd1->orientation == 90 || sd1->orientation == 270)
1761 elm_widget_theme_object_set
1762 (obj, sd1->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(obj));
1764 elm_widget_theme_object_set
1765 (obj, sd1->layout, "ctxpopup", "layout", elm_widget_style_get(obj));
1771 elm_ctxpopup_hover_parent_set(Evas_Object *obj,
1772 Evas_Object *parent)
1774 Evas_Coord x, y, w, h;
1776 ELM_CTXPOPUP_CHECK(obj);
1777 ELM_CTXPOPUP_DATA_GET(obj, sd);
1779 if (!parent) return;
1781 _parent_detach(obj);
1783 evas_object_event_callback_add
1784 (parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
1785 evas_object_event_callback_add
1786 (parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
1787 evas_object_event_callback_add
1788 (parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
1790 sd->parent = parent;
1793 evas_object_geometry_get(parent, &x, &y, &w, &h);
1794 evas_object_move(sd->bg, x, y);
1795 evas_object_resize(sd->bg, w, h);
1797 if (sd->visible) elm_layout_sizing_eval(obj);
1801 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1803 ELM_CTXPOPUP_CHECK(obj) NULL;
1804 ELM_CTXPOPUP_DATA_GET(obj, sd);
1810 elm_ctxpopup_clear(Evas_Object *obj)
1812 ELM_CTXPOPUP_CHECK(obj);
1813 ELM_CTXPOPUP_DATA_GET(obj, sd);
1817 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1821 elm_ctxpopup_horizontal_set(Evas_Object *obj,
1822 Eina_Bool horizontal)
1825 Elm_Ctxpopup_Item *item;
1828 ELM_CTXPOPUP_CHECK(obj);
1829 ELM_CTXPOPUP_DATA_GET(obj, sd);
1831 sd->horizontal = !!horizontal;
1838 elm_box_horizontal_set(sd->box, EINA_FALSE);
1839 elm_scroller_bounce_set(sd->scr, EINA_FALSE, EINA_TRUE);
1843 elm_box_horizontal_set(sd->box, EINA_TRUE);
1844 elm_scroller_bounce_set(sd->scr, EINA_TRUE, EINA_FALSE);
1847 EINA_LIST_FOREACH(sd->items, elist, item)
1849 if (item->label && !item->icon && !horizontal)
1850 _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "text_style_item",
1851 elm_widget_style_get(obj));
1852 else if (item->label && !item->icon && horizontal)
1853 _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1854 "text_style_item_horizontal",
1855 elm_widget_style_get(obj));
1858 edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
1860 edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
1862 _item_disable_hook((Elm_Object_Item *)item);
1865 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1867 if (sd->visible) elm_layout_sizing_eval(obj);
1871 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
1873 ELM_CTXPOPUP_CHECK(obj) EINA_FALSE;
1874 ELM_CTXPOPUP_DATA_GET(obj, sd);
1876 return sd->horizontal;
1879 EAPI Elm_Object_Item *
1880 elm_ctxpopup_item_append(Evas_Object *obj,
1886 Elm_Ctxpopup_Item *item;
1887 Evas_Object *content, *focus_bt;
1889 ELM_CTXPOPUP_CHECK(obj) NULL;
1890 ELM_CTXPOPUP_DATA_GET(obj, sd);
1892 item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
1893 if (!item) return NULL;
1895 elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
1896 elm_widget_item_disable_hook_set(item, _item_disable_hook);
1897 elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
1898 elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
1899 elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
1900 elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
1901 elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
1903 //The first item is appended.
1904 content = elm_object_content_unset(obj);
1905 if (content) evas_object_del(content);
1911 item->base.data = data;
1914 _item_new(item, "icon_text_style_item");
1917 if (!sd->horizontal)
1918 _item_new(item, "text_style_item");
1920 _item_new(item, "text_style_item_horizontal");
1923 _item_new(item, "icon_style_item");
1925 _item_icon_set(item, icon);
1926 _item_label_set(item, label);
1927 focus_bt = _item_in_focusable_button(item);
1928 elm_box_pack_end(sd->box, focus_bt);
1929 sd->items = eina_list_append(sd->items, item);
1931 sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1935 _scroller_size_reset(sd);
1936 _elm_ctxpopup_smart_sizing_eval(obj);
1940 if (_elm_config->access_mode) _access_focusable_button_register(focus_bt, item);
1942 return (Elm_Object_Item *)item;
1946 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
1947 Elm_Ctxpopup_Direction first,
1948 Elm_Ctxpopup_Direction second,
1949 Elm_Ctxpopup_Direction third,
1950 Elm_Ctxpopup_Direction fourth)
1952 ELM_CTXPOPUP_CHECK(obj);
1953 ELM_CTXPOPUP_DATA_GET(obj, sd);
1955 sd->dir_priority[0] = first;
1956 sd->dir_priority[1] = second;
1957 sd->dir_priority[2] = third;
1958 sd->dir_priority[3] = fourth;
1960 if (sd->visible) elm_layout_sizing_eval(obj);
1964 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
1965 Elm_Ctxpopup_Direction *first,
1966 Elm_Ctxpopup_Direction *second,
1967 Elm_Ctxpopup_Direction *third,
1968 Elm_Ctxpopup_Direction *fourth)
1970 ELM_CTXPOPUP_CHECK(obj);
1971 ELM_CTXPOPUP_DATA_GET(obj, sd);
1973 if (first) *first = sd->dir_priority[0];
1974 if (second) *second = sd->dir_priority[1];
1975 if (third) *third = sd->dir_priority[2];
1976 if (fourth) *fourth = sd->dir_priority[3];
1979 EAPI Elm_Ctxpopup_Direction
1980 elm_ctxpopup_direction_get(const Evas_Object *obj)
1982 ELM_CTXPOPUP_CHECK(obj) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1983 ELM_CTXPOPUP_DATA_GET(obj, sd);
1989 elm_ctxpopup_dismiss(Evas_Object *obj)
1991 ELM_CTXPOPUP_CHECK(obj);
1992 ELM_CTXPOPUP_DATA_GET(obj, sd);
1994 _hide_signals_emit(obj, sd->dir);