1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_WIDGET_PROTECTED
6 #define EFL_ACCESS_OBJECT_PROTECTED
7 #define EFL_ACCESS_SELECTION_PROTECTED
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #define EFL_UI_L10N_PROTECTED
10 #define EFL_UI_WIDGET_FOCUS_MANAGER_PROTECTED
11
12 #include <Elementary.h>
13
14 #include "elm_priv.h"
15 #include "elm_widget_menu.h"
16
17 #define MY_CLASS ELM_MENU_CLASS
18
19 #define MY_CLASS_NAME "Elm_Menu"
20 #define MY_CLASS_NAME_LEGACY "elm_menu"
21
22 #define ELM_PRIV_MENU_SIGNALS(cmd) \
23 cmd(SIG_CLICKED, "clicked", "") \
24 cmd(SIG_DISMISSED, "dismissed", "")
25
26 ELM_PRIV_MENU_SIGNALS(ELM_PRIV_STATIC_VARIABLE_DECLARE);
27
28 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
29 ELM_PRIV_MENU_SIGNALS(ELM_PRIV_SMART_CALLBACKS_DESC)
30 {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
31 {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
32 {NULL, NULL}
33 };
34 #undef ELM_PRIV_MENU_SIGNALS
35
36 EOLIAN static void
_elm_menu_efl_ui_l10n_translation_update(Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)37 _elm_menu_efl_ui_l10n_translation_update(Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
38 {
39 Elm_Menu_Item_Data *it;
40 Eina_List *l;
41
42 EINA_LIST_FOREACH(sd->items, l, it)
43 elm_wdg_item_translate(EO_OBJ(it));
44 }
45
46 static void _item_del(Elm_Object_Item *eo_item);
47
48 static void
_elm_menu_subitems_clear(Elm_Menu_Item_Data * it)49 _elm_menu_subitems_clear(Elm_Menu_Item_Data *it)
50 {
51 Elm_Object_Item *sub_it;
52
53 EINA_LIST_FREE(it->submenu.items, sub_it)
54 {
55 ELM_MENU_ITEM_DATA_GET(sub_it, item);
56
57 if (item)
58 {
59 item->parent = NULL;
60 _item_del(sub_it);
61 }
62 }
63 }
64
65 static void
_item_del(Elm_Object_Item * eo_item)66 _item_del(Elm_Object_Item *eo_item)
67 {
68 ELM_MENU_ITEM_DATA_GET(eo_item, item);
69
70 _elm_menu_subitems_clear(item);
71 efl_del(eo_item);
72 }
73
74 static void
_submenu_hide(Elm_Menu_Item_Data * item)75 _submenu_hide(Elm_Menu_Item_Data *item)
76 {
77 Eina_List *l;
78 Elm_Object_Item *eo_item2;
79
80 evas_object_hide(item->submenu.hv);
81 item->submenu.open = EINA_FALSE;
82
83 EINA_LIST_FOREACH(item->submenu.items, l, eo_item2)
84 {
85 ELM_MENU_ITEM_DATA_GET(eo_item2, item2);
86 if (item2->submenu.open) _submenu_hide(item2);
87 }
88 }
89
90 static void
_elm_menu_item_elm_widget_item_disable(Eo * eo_item,Elm_Menu_Item_Data * item)91 _elm_menu_item_elm_widget_item_disable(Eo *eo_item, Elm_Menu_Item_Data *item)
92 {
93 if (elm_object_item_disabled_get((Elm_Object_Item*)eo_item))
94 {
95 elm_layout_signal_emit(VIEW(item), "elm,state,disabled", "elm");
96 if (item->submenu.open) _submenu_hide(item);
97 }
98 else
99 elm_layout_signal_emit(VIEW(item), "elm,state,enabled", "elm");
100
101 if (item->dbus_menu) _elm_dbus_menu_update(item->dbus_menu);
102 edje_object_message_signal_process(elm_layout_edje_get(VIEW(item)));
103 }
104
105 static void
_elm_menu_item_elm_widget_item_signal_emit(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item,const char * emission,const char * source)106 _elm_menu_item_elm_widget_item_signal_emit(Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *item,
107 const char *emission,
108 const char *source)
109 {
110 elm_layout_signal_emit(VIEW(item), emission, source);
111 }
112
113 static inline void
_parent_geometry_get(Elm_Menu_Data * sd,int * x,int * y,int * w,int * h)114 _parent_geometry_get(Elm_Menu_Data *sd, int *x, int *y, int *w, int *h)
115 {
116 Eina_Rect r;
117
118 r = efl_gfx_entity_geometry_get(sd->parent);
119 if (efl_isa(sd->parent, EFL_UI_WIN_CLASS))
120 {
121 if (sd->menu_bar && efl_canvas_object_is_frame_object_get(sd->obj))
122 r.pos = efl_gfx_entity_position_get(sd->obj);
123 else
124 r.pos = EINA_POSITION2D(0, 0);
125 }
126 if (x) *x = r.x;
127 if (y) *y = r.y;
128 if (w) *w = r.w;
129 if (h) *h = r.h;
130 }
131
132 static void
_submenu_sizing_eval(Elm_Menu_Item_Data * parent_it)133 _submenu_sizing_eval(Elm_Menu_Item_Data *parent_it)
134 {
135 Eina_List *l;
136 Elm_Object_Item *eo_item;
137 Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2,
138 h2, bx, by, bw, bh, px, py, pw, ph;
139 ELM_MENU_DATA_GET_OR_RETURN(WIDGET(parent_it), sd);
140
141 EINA_LIST_FOREACH(parent_it->submenu.items, l, eo_item)
142 {
143 ELM_MENU_ITEM_DATA_GET(eo_item, item);
144 elm_layout_sizing_eval(VIEW(item));
145 if (_elm_config->atspi_mode)
146 efl_access_state_changed_signal_emit(eo_item, EFL_ACCESS_STATE_TYPE_SHOWING, EINA_TRUE);
147 }
148
149
150 evas_object_geometry_get
151 (parent_it->submenu.location, &x_p, &y_p, &w_p, &h_p);
152 evas_object_geometry_get(VIEW(parent_it), &x2, &y2, &w2, &h2);
153 evas_object_geometry_get(parent_it->submenu.bx, &bx, &by, &bw, &bh);
154 _parent_geometry_get(sd, &px, &py, &pw, &ph);
155
156 if (sd->menu_bar && !parent_it->parent)
157 {
158 x_p = x2;
159 y_p = y2 + h2;
160 }
161 else
162 {
163 x_p = x2 + w2;
164 y_p = y2;
165 }
166
167 /* If it overflows on the right, adjust the x */
168 if ((x_p + bw > px + pw) || efl_ui_mirrored_get(WIDGET(parent_it)))
169 x_p = x2 - bw;
170
171 /* If it overflows on the left, adjust the x - usually only happens
172 * with an RTL interface */
173 if (x_p < px)
174 x_p = x2 + w2;
175
176 /* If after all the adjustments it still overflows, fix it */
177 if (x_p + bw > px + pw)
178 x_p = x2 - bw;
179
180 if (y_p + bh > py + ph)
181 y_p -= y_p + bh - (py + ph);
182
183 if (sd->menu_bar && (y_p < py))
184 y_p = py;
185
186 evas_object_geometry_set(parent_it->submenu.location, x_p, y_p, bw, h_p);
187 evas_object_size_hint_min_set(parent_it->submenu.location, bw, h_p);
188 evas_object_size_hint_max_set(parent_it->submenu.location, bw, h_p);
189 elm_hover_target_set(parent_it->submenu.hv, parent_it->submenu.location);
190
191 EINA_LIST_FOREACH(parent_it->submenu.items, l, eo_item)
192 {
193 ELM_MENU_ITEM_DATA_GET(eo_item, item);
194 if (item->submenu.open) _submenu_sizing_eval(item);
195 }
196 }
197
198 static void
_sizing_eval(Evas_Object * obj)199 _sizing_eval(Evas_Object *obj)
200 {
201 Eina_List *l;
202 Elm_Object_Item *eo_item;
203 Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2, h2, bw, bh;
204 Elm_Widget_Smart_Data *hover;
205
206 ELM_MENU_DATA_GET(obj, sd);
207
208 if (!sd->parent) return;
209
210 EINA_LIST_FOREACH(sd->items, l, eo_item)
211 {
212 ELM_MENU_ITEM_DATA_GET(eo_item, item);
213 elm_layout_sizing_eval(VIEW(item));
214 }
215
216 evas_object_geometry_get(sd->location, NULL, NULL, &w_p, &h_p);
217 _parent_geometry_get(sd, &x2, &y2, &w2, &h2);
218 evas_object_geometry_get(sd->bx, NULL, NULL, &bw, &bh);
219
220 x_p = sd->xloc;
221 y_p = sd->yloc;
222
223 if (efl_ui_mirrored_get(obj)) x_p -= w_p;
224
225 if (x_p + bw > x2 + w2) x_p -= x_p + bw - (x2 + w2);
226 if (x_p < x2) x_p = x2;
227
228 if (y_p + h_p + bh > y2 + h2) y_p -= y_p + h_p + bh - (y2 + h2);
229 if (y_p < y2) y_p = y2;
230
231 efl_gfx_entity_geometry_set(sd->location, EINA_RECT(x_p, y_p, bw, h_p));
232 evas_object_size_hint_min_set(sd->location, bw, h_p);
233 evas_object_size_hint_max_set(sd->location, bw, h_p);
234 elm_hover_target_set(sd->hv, sd->location);
235
236 hover = efl_data_scope_get(sd->hv, EFL_UI_WIDGET_CLASS);
237 edje_object_part_geometry_get(hover->resize_obj, "bottom", NULL,
238 NULL, &bw, &bh);
239 evas_object_size_hint_min_set(obj, bw, bh);
240
241 EINA_LIST_FOREACH(sd->items, l, eo_item)
242 {
243 ELM_MENU_ITEM_DATA_GET(eo_item, item);
244 if (item->submenu.open) _submenu_sizing_eval(item);
245 }
246 }
247
248 EOLIAN static Eina_Error
_elm_menu_efl_ui_widget_theme_apply(Eo * obj,Elm_Menu_Data * sd)249 _elm_menu_efl_ui_widget_theme_apply(Eo *obj, Elm_Menu_Data *sd)
250 {
251 Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
252
253 Eina_List *l, *_l, *_ll, *ll = NULL;
254 Elm_Object_Item *eo_item;
255 const char *s;
256 char style[1024];
257
258 int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
259 if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
260
261 if (sd->menu_bar)
262 snprintf(style, sizeof(style), "main_menu/%s", elm_widget_style_get(obj));
263 else
264 snprintf(style, sizeof(style), "menu/%s", elm_widget_style_get(obj));
265 elm_object_style_set(sd->hv, style);
266
267 ll = eina_list_append(ll, sd->items);
268 EINA_LIST_FOREACH(ll, _ll, l)
269 {
270 EINA_LIST_FOREACH(l, _l, eo_item)
271 {
272 ELM_MENU_ITEM_DATA_GET(eo_item, item);
273 ll = eina_list_append(ll, item->submenu.items);
274 if (item->separator)
275 {
276 if (!elm_layout_theme_set(VIEW(item), "menu", "separator",
277 elm_widget_style_get(obj)))
278 CRI("Failed to set layout!");
279 }
280 else if (item->submenu.bx)
281 {
282 if (sd->menu_bar && !item->parent) s = "main_menu_submenu";
283 else s = "item_with_submenu";
284
285 if (!elm_layout_theme_set(VIEW(item), "menu", s,
286 elm_widget_style_get(obj)))
287 CRI("Failed to set layout!");
288 snprintf(style, sizeof(style), "menu/%s", elm_widget_style_get(WIDGET(item)));
289 elm_object_style_set(item->submenu.hv, style);
290
291 elm_object_item_text_set(eo_item,
292 item->label);
293 if (item->icon_str)
294 elm_menu_item_icon_name_set(eo_item,
295 item->icon_str);
296 }
297 else
298 {
299 if (!elm_layout_theme_set(VIEW(item), "menu", "item",
300 elm_widget_style_get(obj)))
301 CRI("Failed to set layout!");
302
303 elm_object_item_text_set(eo_item,
304 item->label);
305 if (item->icon_str)
306 elm_menu_item_icon_name_set(eo_item,
307 item->icon_str);
308 }
309 elm_wdg_item_disable(eo_item);
310 /* SEOZ
311 edje_object_scale_set
312 (VIEW(item), efl_gfx_entity_scale_get(obj) *
313 elm_config_scale_get());
314 */
315 }
316 }
317
318 eina_list_free(ll); //fixme: test
319
320 _sizing_eval(obj);
321
322 return int_ret;
323 }
324
325 EOLIAN static void
_elm_menu_item_elm_widget_item_part_text_set(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item,const char * part,const char * label)326 _elm_menu_item_elm_widget_item_part_text_set(Eo *eo_item EINA_UNUSED,
327 Elm_Menu_Item_Data *item,
328 const char *part,
329 const char *label)
330 {
331 if (part && strcmp(part, "default")) return;
332
333 eina_stringshare_replace(&item->label, label);
334
335 if (label)
336 elm_layout_signal_emit(VIEW(item), "elm,state,text,visible", "elm");
337 else
338 elm_layout_signal_emit(VIEW(item), "elm,state,text,hidden", "elm");
339
340 edje_object_message_signal_process(elm_layout_edje_get(VIEW(item)));
341 elm_layout_text_set(VIEW(item), "elm.text", label);
342
343 _sizing_eval(WIDGET(item));
344 }
345
346 EOLIAN static const char *
_elm_menu_item_elm_widget_item_part_text_get(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * it,const char * part)347 _elm_menu_item_elm_widget_item_part_text_get(const Eo *eo_item EINA_UNUSED,
348 Elm_Menu_Item_Data *it,
349 const char *part)
350 {
351 if (part && strcmp(part, "default")) return NULL;
352
353 return it->label;
354 }
355
356 EOLIAN static void
_elm_menu_item_elm_widget_item_part_content_set(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item,const char * part,Evas_Object * content)357 _elm_menu_item_elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED,
358 Elm_Menu_Item_Data *item,
359 const char *part,
360 Evas_Object *content)
361 {
362 if (part && strcmp(part, "default")) return;
363
364 if (content == item->content) return;
365
366 evas_object_del(item->content);
367 item->content = content;
368 if (item->content)
369 elm_layout_content_set(VIEW(item), "elm.swallow.content", item->content);
370
371 _sizing_eval(WIDGET(item));
372 }
373
374 EOLIAN static Evas_Object *
_elm_menu_item_elm_widget_item_part_content_get(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * it,const char * part)375 _elm_menu_item_elm_widget_item_part_content_get(const Eo *eo_item EINA_UNUSED,
376 Elm_Menu_Item_Data *it,
377 const char *part)
378 {
379 if (part && strcmp(part, "default")) return NULL;
380
381 return it->content;
382 }
383
384 static void
_menu_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)385 _menu_resize_cb(void *data,
386 Evas *e EINA_UNUSED,
387 Evas_Object *obj EINA_UNUSED,
388 void *event_info EINA_UNUSED)
389 {
390 _sizing_eval(data);
391 }
392
393 static void
_parent_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)394 _parent_resize_cb(void *data,
395 Evas *e EINA_UNUSED,
396 Evas_Object *obj EINA_UNUSED,
397 void *event_info EINA_UNUSED)
398 {
399 _sizing_eval(data);
400 }
401
402 static void
_parent_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)403 _parent_del_cb(void *data,
404 Evas *e EINA_UNUSED,
405 Evas_Object *obj,
406 void *event_info EINA_UNUSED)
407 {
408 ELM_WIDGET_DATA_GET_OR_RETURN(data, wd);
409
410 evas_object_event_callback_del_full
411 (obj, EVAS_CALLBACK_RESIZE, _parent_resize_cb, data);
412 }
413
414 static void
_item_move_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)415 _item_move_resize_cb(void *data,
416 Evas *e EINA_UNUSED,
417 Evas_Object *obj EINA_UNUSED,
418 void *event_info EINA_UNUSED)
419 {
420 Elm_Menu_Item_Data *item = data;
421
422 if (item->submenu.open) _submenu_sizing_eval(item);
423 }
424
425 static void
_menu_hide(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)426 _menu_hide(void *data,
427 Evas_Object *obj EINA_UNUSED,
428 void *event_info EINA_UNUSED)
429 {
430 Eina_List *l;
431 Elm_Object_Item *eo_item2;
432
433 ELM_MENU_DATA_GET(data, sd);
434
435 if (!sd->menu_bar)
436 {
437 evas_object_hide(sd->hv);
438 evas_object_hide(data);
439 }
440
441 EINA_LIST_FOREACH(sd->items, l, eo_item2)
442 {
443 ELM_MENU_ITEM_DATA_GET(eo_item2, item2);
444 if (item2->submenu.open) _submenu_hide(item2);
445 }
446 }
447
448 static void
_hover_dismissed_cb(void * data,const Efl_Event * event)449 _hover_dismissed_cb(void *data, const Efl_Event *event)
450 {
451 _menu_hide(data, event->object, event->info);
452 evas_object_smart_callback_call
453 ( data, "clicked", NULL);
454 efl_event_callback_legacy_call(data, ELM_MENU_EVENT_DISMISSED, NULL);
455 }
456
457 static void
_submenu_open_cb(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)458 _submenu_open_cb(void *data,
459 Evas_Object *obj EINA_UNUSED,
460 const char *emission EINA_UNUSED,
461 const char *source EINA_UNUSED)
462 {
463 Elm_Menu_Item_Data *item = data;
464
465 item->submenu.open = EINA_TRUE;
466 evas_object_show(item->submenu.hv);
467 _submenu_sizing_eval(item);
468 }
469
470 void
_elm_dbus_menu_item_select_cb(Elm_Object_Item * obj_item)471 _elm_dbus_menu_item_select_cb(Elm_Object_Item *obj_item)
472 {
473 ELM_MENU_ITEM_DATA_GET(obj_item, item);
474 if (item->func) item->func((void *)(WIDGET_ITEM_DATA_GET(EO_OBJ(item))), WIDGET(item), obj_item);
475 }
476
477 static void
_menu_item_select_cb(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)478 _menu_item_select_cb(void *data,
479 Evas_Object *obj EINA_UNUSED,
480 const char *emission EINA_UNUSED,
481 const char *source EINA_UNUSED)
482 {
483 Elm_Menu_Item_Data *item = data;
484
485 if (item->submenu.items)
486 {
487 if (!item->submenu.open) _submenu_open_cb(item, NULL, NULL, NULL);
488 else _submenu_hide(item);
489 }
490 else _menu_hide(WIDGET(item), NULL, NULL);
491
492 if (item->func) item->func((void *)(WIDGET_ITEM_DATA_GET(EO_OBJ(item))), WIDGET(item), EO_OBJ(item));
493 }
494
495 static void
_menu_item_activate_cb(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)496 _menu_item_activate_cb(void *data,
497 Evas_Object *obj EINA_UNUSED,
498 const char *emission EINA_UNUSED,
499 const char *source EINA_UNUSED)
500 {
501 Eina_List *l;
502 Elm_Object_Item *eo_item2;
503 Elm_Menu_Item_Data *item = data;
504
505 item->selected = 1;
506 if (item->parent)
507 {
508 EINA_LIST_FOREACH(item->parent->submenu.items, l, eo_item2)
509 {
510 if (eo_item2 != EO_OBJ(item))
511 elm_menu_item_selected_set(eo_item2, 0);
512 }
513 efl_access_object_event_emit(EO_OBJ(item->parent), EFL_ACCESS_SELECTION_EVENT_ACCESS_SELECTION_CHANGED, NULL);
514 }
515 else
516 {
517 Eina_Bool was_open = EINA_FALSE;
518 ELM_MENU_DATA_GET(WIDGET(item), sd);
519 EINA_LIST_FOREACH(sd->items, l, eo_item2)
520 {
521 if (eo_item2 != EO_OBJ(item))
522 {
523 ELM_MENU_ITEM_DATA_GET(eo_item2, item2);
524 was_open |= item2->submenu.open;
525 elm_menu_item_selected_set(eo_item2, 0);
526 }
527 }
528 efl_access_object_event_emit(WIDGET(item), EFL_ACCESS_SELECTION_EVENT_ACCESS_SELECTION_CHANGED, NULL);
529 if (sd->menu_bar && was_open)
530 _menu_item_select_cb(item, NULL, NULL, NULL);
531 }
532 if (_elm_config->atspi_mode)
533 efl_access_state_changed_signal_emit(EO_OBJ(item), EFL_ACCESS_STATE_TYPE_SELECTED, EINA_TRUE);
534 }
535
536 static void
_menu_item_inactivate_cb(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)537 _menu_item_inactivate_cb(void *data,
538 Evas_Object *obj EINA_UNUSED,
539 const char *emission EINA_UNUSED,
540 const char *source EINA_UNUSED)
541 {
542 Elm_Menu_Item_Data *item = data;
543
544 item->selected = 0;
545 if (item->submenu.open) _submenu_hide(item);
546 if (_elm_config->atspi_mode)
547 efl_access_state_changed_signal_emit(EO_OBJ(item), EFL_ACCESS_STATE_TYPE_SELECTED, EINA_FALSE);
548 }
549
550 static void
_block_menu(void * _sd,const Efl_Event * event EINA_UNUSED)551 _block_menu(void *_sd, const Efl_Event *event EINA_UNUSED)
552 {
553 const Eina_List *l;
554 Elm_Object_Item *eo_current;
555 Elm_Menu_Data *sd = _sd;
556 Eina_List *items = sd->items;
557 EINA_LIST_FOREACH(items, l, eo_current)
558 {
559 ELM_MENU_ITEM_DATA_GET(eo_current, current);
560 if (!current->blocked) current->was_enabled = !elm_wdg_item_disabled_get(eo_current);
561 current->blocked = EINA_TRUE;
562 elm_object_item_disabled_set(eo_current, EINA_TRUE);
563 }
564 }
565
566 static void
_unblock_menu(void * _sd,const Efl_Event * event EINA_UNUSED)567 _unblock_menu(void *_sd, const Efl_Event *event EINA_UNUSED)
568 {
569 const Eina_List *l;
570 Elm_Object_Item *eo_current;
571 Elm_Menu_Data *sd = _sd;
572 Eina_List *items = sd->items;
573 EINA_LIST_FOREACH(items, l, eo_current)
574 {
575 ELM_MENU_ITEM_DATA_GET(eo_current, current);
576 elm_object_item_disabled_set(eo_current, !current->was_enabled);
577 current->blocked = EINA_FALSE;
578 }
579 }
580
581 EOLIAN static void
_elm_menu_efl_gfx_entity_visible_set(Eo * obj EINA_UNUSED,Elm_Menu_Data * sd,Eina_Bool vis)582 _elm_menu_efl_gfx_entity_visible_set(Eo *obj EINA_UNUSED, Elm_Menu_Data *sd, Eina_Bool vis)
583 {
584 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
585 return;
586
587 efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis);
588 if (vis) efl_gfx_entity_visible_set(sd->hv, EINA_TRUE);
589 }
590
591 static void
_item_obj_create(Elm_Menu_Item_Data * item)592 _item_obj_create(Elm_Menu_Item_Data *item)
593 {
594 VIEW_SET(item, elm_layout_add(WIDGET(item)));
595 efl_access_object_access_type_set(VIEW(item), EFL_ACCESS_TYPE_SKIPPED);
596 evas_object_size_hint_weight_set
597 (VIEW(item), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
598 evas_object_size_hint_fill_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
599 if (!elm_layout_theme_set(VIEW(item), "menu", "item",
600 elm_widget_style_get(WIDGET(item))))
601 CRI("Failed to set layout!");
602 else
603 {
604 elm_layout_signal_callback_add(VIEW(item), "elm,action,click", "*",
605 _menu_item_select_cb, item);
606 elm_layout_signal_callback_add(VIEW(item), "elm,action,activate", "*",
607 _menu_item_activate_cb, item);
608 elm_layout_signal_callback_add(VIEW(item), "elm,action,inactivate", "*",
609 _menu_item_inactivate_cb,
610 item);
611 evas_object_show(VIEW(item));
612 }
613 }
614
615 static void
_item_separator_obj_create(Elm_Menu_Item_Data * item)616 _item_separator_obj_create(Elm_Menu_Item_Data *item)
617 {
618 VIEW_SET(item, elm_layout_add(WIDGET(item)));
619 efl_access_object_access_type_set(VIEW(item), EFL_ACCESS_TYPE_SKIPPED);
620 evas_object_size_hint_weight_set
621 (VIEW(item), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
622 evas_object_size_hint_fill_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
623 if (!elm_layout_theme_set(VIEW(item), "menu", "separator",
624 elm_widget_style_get(WIDGET(item))))
625 CRI("Failed to set layout!");
626 else
627 {
628 elm_layout_signal_callback_add
629 (VIEW(item), "elm,action,activate", "*", _menu_item_activate_cb, item);
630 evas_object_show(VIEW(item));
631 }
632 }
633
634 static void
_item_submenu_obj_create(Elm_Menu_Item_Data * item)635 _item_submenu_obj_create(Elm_Menu_Item_Data *item)
636 {
637 ELM_MENU_DATA_GET(WIDGET(item), sd);
638 Evas_Object *hv, *bx;
639 char style[1024];
640
641 item->submenu.location = elm_icon_add(sd->bx);
642 efl_access_object_access_type_set(item->submenu.location, EFL_ACCESS_TYPE_DISABLED);
643 item->submenu.hv = hv = elm_hover_add(sd->bx);
644 efl_access_object_access_type_set(item->submenu.hv, EFL_ACCESS_TYPE_SKIPPED);
645 efl_ui_mirrored_set(hv, EINA_FALSE);
646 elm_hover_target_set(hv, item->submenu.location);
647 elm_hover_parent_set(hv, sd->parent);
648
649 if (sd->menu_bar && !item->parent)
650 {
651 snprintf(style, sizeof(style), "main_menu_submenu/%s", elm_widget_style_get(WIDGET(item)));
652 elm_object_style_set(hv, style);
653 efl_event_callback_add
654 (hv, ELM_HOVER_EVENT_DISMISSED, _hover_dismissed_cb, WIDGET(item));
655 }
656 else
657 {
658 snprintf(style, sizeof(style), "submenu/%s", elm_widget_style_get(WIDGET(item)));
659 elm_object_style_set(hv, style);
660 }
661
662 item->submenu.bx = bx = elm_box_add(sd->bx);
663 efl_ui_mirrored_set(bx, EINA_FALSE);
664 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
665 evas_object_show(bx);
666 elm_object_part_content_set
667 (hv, elm_hover_best_content_location_get
668 (hv, ELM_HOVER_AXIS_VERTICAL), bx);
669
670 if (sd->menu_bar && !item->parent)
671 {
672 if (!elm_layout_theme_set(VIEW(item), "menu",
673 "main_menu_submenu",
674 elm_widget_style_get(WIDGET(item))))
675 CRI("Failed to set layout!");
676 }
677 else
678 {
679 if (!elm_layout_theme_set(VIEW(item), "menu",
680 "item_with_submenu",
681 elm_widget_style_get(WIDGET(item))))
682 CRI("Failed to set layout!");
683 }
684
685 elm_object_item_text_set(EO_OBJ(item), item->label);
686
687 if (item->icon_str)
688 elm_menu_item_icon_name_set(EO_OBJ(item), item->icon_str);
689
690 elm_layout_signal_callback_add(VIEW(item), "elm,action,open", "*",
691 _submenu_open_cb, item);
692 evas_object_event_callback_add
693 (VIEW(item), EVAS_CALLBACK_MOVE, _item_move_resize_cb, item);
694 evas_object_event_callback_add
695 (VIEW(item), EVAS_CALLBACK_RESIZE, _item_move_resize_cb, item);
696
697 evas_object_event_callback_add(bx, EVAS_CALLBACK_RESIZE,
698 _menu_resize_cb, WIDGET(item));
699 }
700
701 EOLIAN static void
_elm_menu_efl_canvas_group_group_add(Eo * obj,Elm_Menu_Data * priv)702 _elm_menu_efl_canvas_group_group_add(Eo *obj, Elm_Menu_Data *priv)
703 {
704 efl_canvas_group_add(efl_super(obj, MY_CLASS));
705
706 elm_widget_can_focus_set(obj, EINA_FALSE);
707
708 priv->location = elm_icon_add(obj);
709 efl_access_object_access_type_set(priv->location, EFL_ACCESS_TYPE_DISABLED);
710
711 priv->hv = elm_hover_add(obj);
712 efl_access_object_access_type_set(priv->hv, EFL_ACCESS_TYPE_SKIPPED);
713 efl_ui_mirrored_set(priv->hv, EINA_FALSE);
714
715 elm_object_style_set(priv->hv, "menu/default");
716 efl_event_callback_add
717 (priv->hv, ELM_HOVER_EVENT_DISMISSED, _hover_dismissed_cb, obj);
718
719 priv->bx = elm_box_add(obj);
720 efl_access_object_access_type_set(priv->bx, EFL_ACCESS_TYPE_SKIPPED);
721 efl_ui_mirrored_set(priv->bx, EINA_FALSE);
722 evas_object_size_hint_weight_set
723 (priv->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
724
725 evas_object_event_callback_add
726 (priv->bx, EVAS_CALLBACK_RESIZE, _menu_resize_cb, obj);
727 }
728
729 EOLIAN static void
_elm_menu_efl_canvas_group_group_del(Eo * obj,Elm_Menu_Data * sd)730 _elm_menu_efl_canvas_group_group_del(Eo *obj, Elm_Menu_Data *sd)
731 {
732 Elm_Object_Item *eo_item;
733
734 _elm_dbus_menu_unregister(obj);
735
736 if (sd->parent)
737 {
738 evas_object_event_callback_del_full
739 (sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
740 evas_object_event_callback_del_full
741 (sd->parent, EVAS_CALLBACK_DEL, _parent_del_cb, obj);
742 }
743
744 EINA_LIST_FREE(sd->items, eo_item)
745 _item_del(eo_item);
746
747 evas_object_event_callback_del_full
748 (sd->bx, EVAS_CALLBACK_RESIZE, _menu_resize_cb, obj);
749
750 evas_object_del(sd->hv);
751 evas_object_del(sd->location);
752
753 efl_canvas_group_del(efl_super(obj, MY_CLASS));
754 }
755
756 void
_elm_menu_menu_bar_hide(Eo * obj)757 _elm_menu_menu_bar_hide(Eo *obj)
758 {
759 ELM_MENU_DATA_GET_OR_RETURN(obj, sd);
760
761 evas_object_hide(sd->hv);
762 evas_object_hide(obj);
763 _menu_hide(obj, NULL, NULL);
764 }
765
766 void
_elm_menu_menu_bar_set(Eo * obj,Eina_Bool menu_bar)767 _elm_menu_menu_bar_set(Eo *obj, Eina_Bool menu_bar)
768 {
769 Eina_List *l;
770 Elm_Object_Item *eo_item;
771 char style[1024];
772
773 ELM_MENU_DATA_GET_OR_RETURN(obj, sd);
774
775 if (menu_bar == sd->menu_bar) return;
776
777 elm_box_horizontal_set(sd->bx, menu_bar);
778 elm_box_homogeneous_set(sd->bx, !menu_bar);
779 sd->menu_bar = menu_bar;
780
781 if (sd->menu_bar)
782 snprintf(style, sizeof(style), "main_menu/%s", elm_widget_style_get(obj));
783 else
784 snprintf(style, sizeof(style), "menu/%s", elm_widget_style_get(obj));
785 elm_object_style_set(sd->hv, style);
786
787 EINA_LIST_FOREACH(sd->items, l, eo_item)
788 {
789 ELM_MENU_ITEM_DATA_GET(eo_item, item);
790 if (!item->submenu.bx) continue;
791
792 if (menu_bar)
793 {
794 efl_event_callback_add
795 (item->submenu.hv, EFL_INPUT_EVENT_CLICKED, _hover_dismissed_cb, WIDGET(item));
796 snprintf(style, sizeof(style), "main_menu_submenu//%s", elm_widget_style_get(obj));
797 elm_object_style_set(item->submenu.hv, style);
798 }
799 else
800 {
801 efl_event_callback_del(item->submenu.hv, EFL_INPUT_EVENT_CLICKED, _hover_dismissed_cb, WIDGET(item));
802 snprintf(style, sizeof(style), "submenu/%s", elm_widget_style_get(obj));
803 elm_object_style_set(item->submenu.hv, style);
804 }
805 }
806
807 efl_ui_widget_theme_apply(obj);
808 }
809
810 EAPI Evas_Object *
elm_menu_add(Evas_Object * parent)811 elm_menu_add(Evas_Object *parent)
812 {
813 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
814 return elm_legacy_add(MY_CLASS, parent);
815 }
816
817 EOLIAN static Efl_Ui_Focus_Manager*
_elm_menu_efl_ui_widget_focus_manager_focus_manager_create(Eo * obj EINA_UNUSED,Elm_Menu_Data * pd EINA_UNUSED,Efl_Ui_Focus_Object * root)818 _elm_menu_efl_ui_widget_focus_manager_focus_manager_create(Eo *obj EINA_UNUSED, Elm_Menu_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root)
819 {
820 Efl_Ui_Focus_Manager *manager;
821
822 manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj,
823 efl_ui_focus_manager_root_set(efl_added, root)
824 );
825
826 return manager;
827 }
828
829 static void
_parent_setup(Eo * obj,Elm_Menu_Data * sd,Evas_Object * parent)830 _parent_setup(Eo *obj, Elm_Menu_Data *sd, Evas_Object *parent)
831 {
832 Eina_List *l, *_l, *_ll, *ll = NULL;
833 Elm_Object_Item *eo_item;
834
835 if (sd->parent == parent) return;
836 if (sd->parent)
837 {
838 evas_object_event_callback_del_full
839 (sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
840 evas_object_event_callback_del_full
841 (sd->parent, EVAS_CALLBACK_DEL, _parent_del_cb, obj);
842 }
843 sd->parent = parent;
844 if (sd->parent)
845 {
846 evas_object_event_callback_add
847 (sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
848 evas_object_event_callback_add
849 (sd->parent, EVAS_CALLBACK_DEL, _parent_del_cb, obj);
850 }
851 elm_hover_parent_set(sd->hv, parent);
852
853 ll = eina_list_append(ll, sd->items);
854 EINA_LIST_FOREACH(ll, _ll, l)
855 {
856 EINA_LIST_FOREACH(l, _l, eo_item)
857 {
858 ELM_MENU_ITEM_DATA_GET(eo_item, item);
859 if (item->submenu.hv)
860 {
861 elm_hover_parent_set(item->submenu.hv, parent);
862 ll = eina_list_append(ll, item->submenu.items);
863 }
864 }
865 }
866
867 eina_list_free(ll);
868
869 _sizing_eval(obj);
870 }
871
872 EOLIAN static Eo *
_elm_menu_efl_object_constructor(Eo * obj,Elm_Menu_Data * sd)873 _elm_menu_efl_object_constructor(Eo *obj, Elm_Menu_Data *sd)
874 {
875 Eo *parent = NULL;
876
877 obj = efl_constructor(efl_super(obj, MY_CLASS));
878 _parent_setup(obj, sd, efl_parent_get(obj));
879 efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
880 evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
881 parent = efl_parent_get(obj);
882 efl_access_object_role_set(obj, EFL_ACCESS_ROLE_MENU);
883
884 elm_menu_parent_set(obj, parent);
885 elm_hover_target_set(sd->hv, sd->location);
886 elm_layout_content_set
887 (sd->hv, elm_hover_best_content_location_get
888 (sd->hv, ELM_HOVER_AXIS_VERTICAL), sd->bx);
889
890 _sizing_eval(obj);
891 efl_event_callback_add
892 (obj, ELM_MENU_EVENT_ELM_ACTION_BLOCK_MENU, _block_menu, sd);
893 efl_event_callback_add
894 (obj, ELM_MENU_EVENT_ELM_ACTION_UNBLOCK_MENU, _unblock_menu, sd);
895
896 sd->obj = obj;
897 return obj;
898 }
899
900 EOLIAN static void
_elm_menu_efl_object_destructor(Eo * obj,Elm_Menu_Data * sd)901 _elm_menu_efl_object_destructor(Eo *obj, Elm_Menu_Data *sd)
902 {
903 Eina_List *itr, *itr2;
904 Elm_Object_Item *eo_item;
905 EINA_LIST_FOREACH_SAFE(sd->items, itr, itr2, eo_item)
906 efl_del(eo_item);
907
908 efl_destructor(efl_super(obj, MY_CLASS));
909 }
910
911 EAPI void
elm_menu_parent_set(Evas_Object * obj,Evas_Object * parent)912 elm_menu_parent_set(Evas_Object *obj,
913 Evas_Object *parent)
914 {
915 ELM_MENU_CHECK(obj);
916 ELM_MENU_DATA_GET(obj, sd);
917 efl_ui_widget_sub_object_add(parent, obj);
918 _parent_setup(obj, sd, parent);
919 }
920
921 EAPI Evas_Object *
elm_menu_parent_get(const Evas_Object * obj)922 elm_menu_parent_get(const Evas_Object *obj)
923 {
924 ELM_MENU_CHECK(obj) NULL;
925 return efl_ui_widget_parent_get(obj);
926 }
927
928 EOLIAN static void
_elm_menu_relative_move(Eo * obj,Elm_Menu_Data * sd,Evas_Coord x,Evas_Coord y)929 _elm_menu_relative_move(Eo *obj, Elm_Menu_Data *sd, Evas_Coord x, Evas_Coord y)
930 {
931 sd->xloc = x;
932 sd->yloc = y;
933 _sizing_eval(obj);
934 }
935
936 EOLIAN static void
_elm_menu_open(Eo * obj,Elm_Menu_Data * sd EINA_UNUSED)937 _elm_menu_open(Eo *obj, Elm_Menu_Data *sd EINA_UNUSED)
938 {
939 evas_object_show(obj);
940 }
941
942 EOLIAN static void
_elm_menu_close(Eo * obj,Elm_Menu_Data * sd)943 _elm_menu_close(Eo *obj, Elm_Menu_Data *sd)
944 {
945 _menu_hide(obj, sd->hv, NULL);
946 }
947
948 EOLIAN static Evas_Object *
_elm_menu_item_object_get(const Eo * eo_it EINA_UNUSED,Elm_Menu_Item_Data * it)949 _elm_menu_item_object_get(const Eo *eo_it EINA_UNUSED, Elm_Menu_Item_Data *it)
950 {
951 return VIEW(it);
952 }
953
954 static void
_item_clone(Evas_Object * obj,Elm_Object_Item * parent,Elm_Object_Item * eo_item)955 _item_clone(Evas_Object *obj,
956 Elm_Object_Item *parent,
957 Elm_Object_Item *eo_item)
958 {
959 Elm_Object_Item *new_item;
960 Elm_Object_Item *subitem;
961 Eina_List *iter;
962
963 ELM_MENU_ITEM_DATA_GET(eo_item, item);
964 if (item->separator)
965 new_item = elm_menu_item_separator_add(obj, parent);
966 else
967 new_item = elm_menu_item_add(obj,
968 parent,
969 item->icon_str,
970 item->label,
971 item->func,
972 WIDGET_ITEM_DATA_GET(EO_OBJ(item)));
973
974 Eina_Bool disabled;
975 disabled = elm_wdg_item_disabled_get(eo_item);
976 elm_wdg_item_disabled_set(new_item, disabled);
977
978 EINA_LIST_FOREACH(item->submenu.items, iter, subitem)
979 _item_clone(obj, new_item, subitem);
980 }
981
982 void
elm_menu_clone(Evas_Object * from_menu,Evas_Object * to_menu,Elm_Object_Item * parent)983 elm_menu_clone(Evas_Object *from_menu,
984 Evas_Object *to_menu,
985 Elm_Object_Item *parent)
986 {
987 Eina_List *iter;
988 Elm_Object_Item *eo_item;
989
990 ELM_MENU_CHECK(from_menu);
991 ELM_MENU_CHECK(to_menu);
992
993 ELM_MENU_DATA_GET_OR_RETURN(from_menu, from_sd);
994
995 EINA_LIST_FOREACH(from_sd->items, iter, eo_item)
996 _item_clone(to_menu, parent, eo_item);
997 }
998
999 static void
_elm_menu_item_add_helper(Evas_Object * obj,Elm_Menu_Item_Data * parent,Elm_Menu_Item_Data * subitem,Elm_Menu_Data * sd)1000 _elm_menu_item_add_helper(Evas_Object *obj,
1001 Elm_Menu_Item_Data *parent,
1002 Elm_Menu_Item_Data *subitem,
1003 Elm_Menu_Data *sd)
1004 {
1005 if (parent)
1006 {
1007 if (!parent->submenu.bx) _item_submenu_obj_create(parent);
1008 elm_box_pack_end(parent->submenu.bx, VIEW(subitem));
1009 parent->submenu.items =
1010 eina_list_append(parent->submenu.items, EO_OBJ(subitem));
1011 subitem->idx = eina_list_count(parent->submenu.items) - 1;
1012 }
1013 else
1014 {
1015 elm_box_pack_end(sd->bx, VIEW(subitem));
1016 sd->items = eina_list_append(sd->items, EO_OBJ(subitem));
1017 subitem->idx = eina_list_count(sd->items) - 1;
1018 }
1019
1020 _sizing_eval(obj);
1021 }
1022
1023 EOLIAN static void
_elm_menu_item_efl_object_destructor(Eo * eo_item,Elm_Menu_Item_Data * item)1024 _elm_menu_item_efl_object_destructor(Eo *eo_item, Elm_Menu_Item_Data *item)
1025 {
1026 ELM_MENU_DATA_GET(WIDGET(item), sd);
1027
1028 _elm_menu_subitems_clear(item);
1029 eina_stringshare_del(item->label);
1030 eina_stringshare_del(item->icon_str);
1031 evas_object_del(item->content);
1032 evas_object_del(item->submenu.hv);
1033 evas_object_del(item->submenu.location);
1034
1035 if (item->parent)
1036 item->parent->submenu.items =
1037 eina_list_remove(item->parent->submenu.items, eo_item);
1038 else
1039 sd->items = eina_list_remove(sd->items, eo_item);
1040
1041 if (sd->dbus_menu)
1042 _elm_dbus_menu_item_delete(sd->dbus_menu, item->dbus_idx);
1043
1044 efl_destructor(efl_super(eo_item, ELM_MENU_ITEM_CLASS));
1045 }
1046
1047 EOLIAN static Eo *
_elm_menu_item_efl_object_constructor(Eo * eo_item,Elm_Menu_Item_Data * item)1048 _elm_menu_item_efl_object_constructor(Eo *eo_item, Elm_Menu_Item_Data *item)
1049 {
1050 eo_item = efl_constructor(efl_super(eo_item, ELM_MENU_ITEM_CLASS));
1051 item->base = efl_data_scope_get(eo_item, ELM_WIDGET_ITEM_CLASS);
1052
1053 return eo_item;
1054 }
1055
1056 EOLIAN static Elm_Object_Item*
_elm_menu_item_add(Eo * obj,Elm_Menu_Data * sd,Elm_Object_Item * parent,const char * icon,const char * label,Evas_Smart_Cb func,const void * data)1057 _elm_menu_item_add(Eo *obj, Elm_Menu_Data *sd, Elm_Object_Item *parent, const char *icon, const char *label, Evas_Smart_Cb func, const void *data)
1058 {
1059 Elm_Object_Item *eo_item;
1060 Evas_Object *icon_obj;
1061
1062 icon_obj = elm_icon_add(obj);
1063 efl_access_object_access_type_set(icon_obj, EFL_ACCESS_TYPE_DISABLED);
1064 if (!icon_obj) return NULL;
1065
1066 eo_item = efl_add(ELM_MENU_ITEM_CLASS, obj);
1067 if (!eo_item)
1068 {
1069 evas_object_del(icon_obj);
1070 return NULL;
1071 }
1072
1073 ELM_MENU_ITEM_DATA_GET(eo_item, it);
1074
1075 WIDGET_ITEM_DATA_SET(eo_item, data);
1076 it->func = func;
1077 it->parent = efl_data_scope_get(parent, ELM_MENU_ITEM_CLASS);
1078 it->content = icon_obj;
1079
1080 _item_obj_create(it);
1081 efl_canvas_object_is_frame_object_set(VIEW(it), efl_canvas_object_is_frame_object_get(obj));
1082 efl_canvas_object_is_frame_object_set(icon_obj, efl_canvas_object_is_frame_object_get(obj));
1083 elm_object_item_text_set(eo_item, label);
1084
1085 elm_layout_content_set(VIEW(it), "elm.swallow.content",
1086 it->content);
1087
1088 if (icon) elm_menu_item_icon_name_set(eo_item, icon);
1089
1090 _elm_menu_item_add_helper(obj, it->parent, it, sd);
1091
1092 if (sd->dbus_menu)
1093 {
1094 it->dbus_idx = _elm_dbus_menu_item_add(sd->dbus_menu, eo_item);
1095 it->dbus_menu = sd->dbus_menu;
1096 }
1097 if (_elm_config->atspi_mode)
1098 {
1099 efl_access_added(eo_item);
1100 efl_access_children_changed_added_signal_emit(parent ? parent : obj, eo_item);
1101 }
1102
1103 return eo_item;
1104 }
1105
1106 EOLIAN static unsigned int
_elm_menu_item_index_get(const Eo * eo_it EINA_UNUSED,Elm_Menu_Item_Data * it)1107 _elm_menu_item_index_get(const Eo *eo_it EINA_UNUSED, Elm_Menu_Item_Data *it)
1108 {
1109 return it->idx;
1110 }
1111
1112 EOLIAN static void
_elm_menu_item_icon_name_set(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item,const char * icon)1113 _elm_menu_item_icon_name_set(Eo *eo_item EINA_UNUSED,
1114 Elm_Menu_Item_Data *item,
1115 const char *icon)
1116 {
1117 char icon_tmp[512];
1118
1119 EINA_SAFETY_ON_NULL_RETURN(icon);
1120
1121 if ((icon[0] != '\0') &&
1122 (snprintf(icon_tmp, sizeof(icon_tmp), "menu/%s", icon) > 0) &&
1123 (elm_icon_standard_set(item->content, icon_tmp) ||
1124 elm_icon_standard_set(item->content, icon)))
1125 {
1126 eina_stringshare_replace(&item->icon_str, icon);
1127 elm_layout_signal_emit(VIEW(item), "elm,state,icon,visible", "elm");
1128 }
1129 else
1130 elm_layout_signal_emit(VIEW(item), "elm,state,icon,hidden", "elm");
1131
1132 edje_object_message_signal_process(elm_layout_edje_get(VIEW(item)));
1133 _sizing_eval(WIDGET(item));
1134 }
1135
1136 EOLIAN static Elm_Object_Item*
_elm_menu_item_separator_add(Eo * obj,Elm_Menu_Data * sd,Elm_Object_Item * eo_p_item)1137 _elm_menu_item_separator_add(Eo *obj, Elm_Menu_Data *sd, Elm_Object_Item *eo_p_item)
1138 {
1139 Elm_Object_Item *eo_subitem;
1140
1141 ELM_MENU_ITEM_DATA_GET(eo_p_item, p_item);
1142 /* don't add a separator as the first item */
1143 if (!sd->items) return NULL;
1144
1145 /* don't allow adding more than one separator in a row */
1146 if (eo_p_item)
1147 {
1148 if (!p_item->submenu.items) return NULL;
1149 eo_subitem = eina_list_last(p_item->submenu.items)->data;
1150 }
1151 else eo_subitem = eina_list_last(sd->items)->data;
1152
1153 ELM_MENU_ITEM_DATA_GET(eo_subitem, subitem);
1154 if (subitem->separator) return NULL;
1155
1156 eo_subitem = efl_add(ELM_MENU_ITEM_CLASS, obj);
1157 if (!eo_subitem) return NULL;
1158
1159 subitem = efl_data_scope_get(eo_subitem, ELM_MENU_ITEM_CLASS);
1160
1161 subitem->separator = EINA_TRUE;
1162 subitem->parent = efl_data_scope_get(eo_p_item, ELM_MENU_ITEM_CLASS);
1163
1164 _item_separator_obj_create(subitem);
1165 _elm_menu_item_add_helper(obj, subitem->parent, subitem, sd);
1166
1167 _sizing_eval(obj);
1168
1169 if (sd->dbus_menu)
1170 subitem->dbus_idx = _elm_dbus_menu_item_add(sd->dbus_menu,
1171 eo_subitem);
1172 return eo_subitem;
1173 }
1174
1175 EOLIAN static const char *
_elm_menu_item_icon_name_get(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item)1176 _elm_menu_item_icon_name_get(const Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *item)
1177 {
1178 return item->icon_str;
1179 }
1180
1181 EOLIAN static Eina_Bool
_elm_menu_item_is_separator(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item)1182 _elm_menu_item_is_separator(const Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *item)
1183 {
1184 return item->separator;
1185 }
1186
1187 EOLIAN static const Eina_List *
_elm_menu_item_subitems_get(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item)1188 _elm_menu_item_subitems_get(const Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *item)
1189 {
1190 return item->submenu.items;
1191 }
1192
1193 EOLIAN static void
_elm_menu_item_subitems_clear(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * it)1194 _elm_menu_item_subitems_clear(Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *it)
1195 {
1196 _elm_menu_subitems_clear(it);
1197 }
1198
1199 EOLIAN static const Eina_List *
_elm_menu_items_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)1200 _elm_menu_items_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
1201 {
1202 return sd->items;
1203 }
1204
1205 EOLIAN static void
_elm_menu_item_selected_set(Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item,Eina_Bool selected)1206 _elm_menu_item_selected_set(Eo *eo_item EINA_UNUSED,
1207 Elm_Menu_Item_Data *item,
1208 Eina_Bool selected)
1209 {
1210 if (selected == item->selected) return;
1211 item->selected = selected;
1212 if (selected)
1213 {
1214 elm_layout_signal_emit(VIEW(item), "elm,state,selected", "elm");
1215 _menu_item_activate_cb(item, NULL, NULL, NULL);
1216 }
1217 else
1218 {
1219 elm_layout_signal_emit(VIEW(item), "elm,state,unselected", "elm");
1220 _menu_item_inactivate_cb(item, NULL, NULL, NULL);
1221 }
1222 edje_object_message_signal_process(elm_layout_edje_get(VIEW(item)));
1223 }
1224
1225 EOLIAN static Eina_Bool
_elm_menu_item_selected_get(const Eo * eo_item EINA_UNUSED,Elm_Menu_Item_Data * item)1226 _elm_menu_item_selected_get(const Eo *eo_item EINA_UNUSED, Elm_Menu_Item_Data *item)
1227 {
1228 return item->selected;
1229 }
1230
1231 EOLIAN static Elm_Object_Item *
_elm_menu_item_prev_get(const Eo * eo_item,Elm_Menu_Item_Data * item)1232 _elm_menu_item_prev_get(const Eo *eo_item, Elm_Menu_Item_Data *item)
1233 {
1234 if (item->parent)
1235 {
1236 Eina_List *l = eina_list_data_find_list
1237 (item->parent->submenu.items, eo_item);
1238 l = eina_list_prev(l);
1239 if (!l) return NULL;
1240 return l->data;
1241 }
1242 else
1243 {
1244 ELM_MENU_DATA_GET(WIDGET(item), sd);
1245 if (!sd || !sd->items) return NULL;
1246 Eina_List *l = eina_list_data_find_list(sd->items, eo_item);
1247 l = eina_list_prev(l);
1248 if (!l) return NULL;
1249 return l->data;
1250 }
1251
1252 return NULL;
1253 }
1254
1255 EOLIAN static Elm_Object_Item *
_elm_menu_item_next_get(const Eo * eo_item,Elm_Menu_Item_Data * item)1256 _elm_menu_item_next_get(const Eo *eo_item, Elm_Menu_Item_Data *item)
1257 {
1258 if (item->parent)
1259 {
1260 Eina_List *l =
1261 eina_list_data_find_list(item->parent->submenu.items, eo_item);
1262 l = eina_list_next(l);
1263 if (!l) return NULL;
1264 return l->data;
1265 }
1266 else
1267 {
1268 ELM_MENU_DATA_GET(WIDGET(item), sd);
1269 if (!sd || !sd->items) return NULL;
1270 Eina_List *l = eina_list_data_find_list(sd->items, eo_item);
1271 l = eina_list_next(l);
1272 if (!l) return NULL;
1273 return l->data;
1274 }
1275
1276 return NULL;
1277 }
1278
1279 EOLIAN static Elm_Object_Item*
_elm_menu_first_item_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)1280 _elm_menu_first_item_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
1281 {
1282 return (sd->items ? sd->items->data : NULL);
1283 }
1284
1285 EOLIAN static Elm_Object_Item*
_elm_menu_last_item_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)1286 _elm_menu_last_item_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
1287 {
1288 Eina_List *l = eina_list_last(sd->items);
1289 return (l ? l->data : NULL);
1290 }
1291
1292 EOLIAN static Elm_Object_Item*
_elm_menu_selected_item_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)1293 _elm_menu_selected_item_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
1294 {
1295 Eina_List *l;
1296 Elm_Object_Item *eo_item;
1297
1298 EINA_LIST_FOREACH(sd->items, l, eo_item)
1299 {
1300 ELM_MENU_ITEM_DATA_GET(eo_item, item);
1301 if (item->selected) return eo_item;
1302 }
1303
1304 return NULL;
1305 }
1306
1307 static void
_elm_menu_class_constructor(Efl_Class * klass)1308 _elm_menu_class_constructor(Efl_Class *klass)
1309 {
1310 evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1311 }
1312
1313 EOLIAN static Eina_List*
_elm_menu_efl_access_object_access_children_get(const Eo * obj,Elm_Menu_Data * sd)1314 _elm_menu_efl_access_object_access_children_get(const Eo *obj, Elm_Menu_Data *sd)
1315 {
1316 Eina_List *ret;
1317 ret = efl_access_object_access_children_get(efl_super(obj, ELM_MENU_CLASS));
1318 return eina_list_merge(eina_list_clone(sd->items), ret);
1319 }
1320
1321 EOLIAN static Eina_List*
_elm_menu_item_efl_access_object_access_children_get(const Eo * obj EINA_UNUSED,Elm_Menu_Item_Data * sd)1322 _elm_menu_item_efl_access_object_access_children_get(const Eo *obj EINA_UNUSED, Elm_Menu_Item_Data *sd)
1323 {
1324 return eina_list_clone(sd->submenu.items);
1325 }
1326
1327 EOLIAN static Eo*
_elm_menu_item_efl_object_parent_get(const Eo * obj,Elm_Menu_Item_Data * sd)1328 _elm_menu_item_efl_object_parent_get(const Eo *obj, Elm_Menu_Item_Data *sd)
1329 {
1330 if (sd->parent) return EO_OBJ(sd->parent);
1331 if (sd->base) return WIDGET(sd);
1332 return efl_parent_get(efl_super(obj, ELM_MENU_ITEM_CLASS));
1333 }
1334
1335 EOLIAN static Efl_Access_Role
_elm_menu_item_efl_access_object_role_get(const Eo * obj EINA_UNUSED,Elm_Menu_Item_Data * sd)1336 _elm_menu_item_efl_access_object_role_get(const Eo *obj EINA_UNUSED, Elm_Menu_Item_Data *sd)
1337 {
1338 return sd->submenu.items ? EFL_ACCESS_ROLE_MENU : EFL_ACCESS_ROLE_MENU_ITEM;
1339 }
1340
1341 EOLIAN static const char*
_elm_menu_item_efl_access_object_i18n_name_get(const Eo * obj,Elm_Menu_Item_Data * sd)1342 _elm_menu_item_efl_access_object_i18n_name_get(const Eo *obj, Elm_Menu_Item_Data *sd)
1343 {
1344 const char *ret;
1345 ret = efl_access_object_i18n_name_get(efl_super(obj, ELM_MENU_ITEM_CLASS));
1346 if (ret) return ret;
1347 return sd->label;
1348 }
1349
1350 EOLIAN static Efl_Access_State_Set
_elm_menu_item_efl_access_object_state_set_get(const Eo * obj EINA_UNUSED,Elm_Menu_Item_Data * sd)1351 _elm_menu_item_efl_access_object_state_set_get(const Eo *obj EINA_UNUSED, Elm_Menu_Item_Data *sd)
1352 {
1353 Efl_Access_State_Set ret;
1354 ret = efl_access_object_state_set_get(efl_super(obj, ELM_MENU_ITEM_CLASS));
1355
1356 STATE_TYPE_SET(ret, EFL_ACCESS_STATE_TYPE_SELECTABLE);
1357
1358 if (sd->selected)
1359 STATE_TYPE_SET(ret, EFL_ACCESS_STATE_TYPE_SELECTED);
1360
1361 return ret;
1362 }
1363
1364 EOLIAN static int
_elm_menu_item_efl_access_selection_selected_children_count_get(const Eo * obj EINA_UNUSED,Elm_Menu_Item_Data * sd)1365 _elm_menu_item_efl_access_selection_selected_children_count_get(const Eo *obj EINA_UNUSED, Elm_Menu_Item_Data *sd)
1366 {
1367 int ret = 0;
1368 Elm_Object_Item *sobj = NULL;
1369 Eina_List *l;
1370
1371 EINA_LIST_FOREACH(sd->submenu.items, l, sobj)
1372 {
1373 if (!sobj) continue;
1374 ELM_MENU_ITEM_DATA_GET(sobj, item);
1375 if (item && item->selected) ret++;
1376 }
1377
1378 return ret;
1379 }
1380
1381 EOLIAN static Eo*
_elm_menu_item_efl_access_selection_selected_child_get(const Eo * obj EINA_UNUSED,Elm_Menu_Item_Data * sd,int child)1382 _elm_menu_item_efl_access_selection_selected_child_get(const Eo *obj EINA_UNUSED, Elm_Menu_Item_Data *sd, int child)
1383 {
1384 int seq = 0;
1385 Elm_Object_Item *sobj = NULL;
1386 Eina_List *l;
1387
1388 EINA_LIST_FOREACH(sd->submenu.items, l, sobj)
1389 {
1390 if (!sobj) continue;
1391 ELM_MENU_ITEM_DATA_GET(sobj, item);
1392
1393 if (item && item->selected)
1394 {
1395 if (child == seq++)
1396 break;
1397 }
1398 }
1399
1400 return sobj;
1401 }
1402
1403 EOLIAN static int
_elm_menu_efl_access_selection_selected_children_count_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd)1404 _elm_menu_efl_access_selection_selected_children_count_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd)
1405 {
1406 Elm_Object_Item *sobj = NULL;
1407 Eina_List *l;
1408 int ret = 0;
1409
1410 EINA_LIST_FOREACH(sd->items, l, sobj)
1411 {
1412 ELM_MENU_ITEM_DATA_GET(sobj, item);
1413 if (item && item->selected) ret++;
1414 }
1415
1416 return ret;
1417 }
1418
1419 EOLIAN static Eo*
_elm_menu_efl_access_selection_selected_child_get(const Eo * obj EINA_UNUSED,Elm_Menu_Data * sd,int child)1420 _elm_menu_efl_access_selection_selected_child_get(const Eo *obj EINA_UNUSED, Elm_Menu_Data *sd, int child)
1421 {
1422 int seq = 0;
1423 Elm_Object_Item *sobj = NULL;
1424 Eina_List *l;
1425
1426 EINA_LIST_FOREACH(sd->items, l, sobj)
1427 {
1428 if (!sobj) continue;
1429 ELM_MENU_ITEM_DATA_GET(sobj, item);
1430
1431 if (item && item->selected)
1432 {
1433 if (child == seq++)
1434 break;
1435 }
1436 }
1437
1438 return sobj;
1439
1440 }
1441
1442 EOLIAN static Efl_Object*
_elm_menu_efl_object_provider_find(const Eo * obj,Elm_Menu_Data * pd,const Efl_Object * klass)1443 _elm_menu_efl_object_provider_find(const Eo *obj, Elm_Menu_Data *pd, const Efl_Object *klass)
1444 {
1445 if (!pd->parent)
1446 return efl_provider_find(efl_super(obj, MY_CLASS), klass);
1447
1448 return efl_provider_find(pd->parent, klass);
1449 }
1450
1451
1452
1453 /* Internal EO APIs and hidden overrides */
1454
1455 #define ELM_MENU_EXTRA_OPS \
1456 EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_menu)
1457
1458 #include "elm_menu_item_eo.c"
1459 #include "elm_menu_eo.c"
1460