1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 #define ELM_WIDGET_PROTECTED
8 #define EFL_UI_L10N_PROTECTED
9 
10 #include <Elementary.h>
11 #include "elm_priv.h"
12 #include "elm_widget_combobox.h"
13 #include "elm_entry_eo.h"
14 #include "elm_genlist_eo.h"
15 #include "elm_hover_eo.h"
16 
17 EOAPI void elm_obj_combobox_hover_begin(Eo *obj);
18 EOAPI void elm_obj_combobox_hover_end(Eo *obj);
19 
20 static const Efl_Event_Description _ELM_COMBOBOX_EVENT_DISMISSED =
21    EFL_EVENT_DESCRIPTION("dismissed");
22 static const Efl_Event_Description _ELM_COMBOBOX_EVENT_EXPANDED =
23    EFL_EVENT_DESCRIPTION("expanded");
24 static const Efl_Event_Description _ELM_COMBOBOX_EVENT_ITEM_SELECTED =
25    EFL_EVENT_DESCRIPTION("item,selected");
26 static const Efl_Event_Description _ELM_COMBOBOX_EVENT_ITEM_PRESSED =
27    EFL_EVENT_DESCRIPTION("item,pressed");
28 static const Efl_Event_Description _ELM_COMBOBOX_EVENT_FILTER_DONE =
29    EFL_EVENT_DESCRIPTION("filter,done");
30 
31 #define ELM_COMBOBOX_EVENT_DISMISSED (&(_ELM_COMBOBOX_EVENT_DISMISSED))
32 #define ELM_COMBOBOX_EVENT_EXPANDED (&(_ELM_COMBOBOX_EVENT_EXPANDED))
33 #define ELM_COMBOBOX_EVENT_ITEM_SELECTED (&(_ELM_COMBOBOX_EVENT_ITEM_SELECTED))
34 #define ELM_COMBOBOX_EVENT_ITEM_PRESSED (&(_ELM_COMBOBOX_EVENT_ITEM_PRESSED))
35 #define ELM_COMBOBOX_EVENT_FILTER_DONE (&(_ELM_COMBOBOX_EVENT_FILTER_DONE))
36 
37 #define MY_CLASS ELM_COMBOBOX_CLASS
38 
39 #define MY_CLASS_NAME "Elm_Combobox"
40 #define MY_CLASS_NAME_LEGACY "elm_combobox"
41 
42 static const char SIG_DISMISSED[] = "dismissed";
43 static const char SIG_EXPANDED[] = "expanded";
44 static const char SIG_ITEM_SELECTED[] = "item,selected";
45 static const char SIG_ITEM_PRESSED[] = "item,pressed";
46 static const char SIG_FILTER_DONE[] = "filter,done";
47 static const char SIG_CLICKED[] = "clicked";
48 
49 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
50    {SIG_DISMISSED, ""},
51    {SIG_EXPANDED, ""},
52    {SIG_ITEM_SELECTED, ""},
53    {SIG_ITEM_PRESSED, ""},
54    {SIG_FILTER_DONE, ""},
55    {SIG_CLICKED, ""}, /**< handled by parent button class */
56    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
57    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
58    {NULL, NULL}
59 };
60 
61 static void _table_resize(void *data);
62 static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
63 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
64 
65 static const Elm_Action key_actions[] = {
66    {"activate", _key_action_activate},
67    {"move", _key_action_move},
68    {NULL, NULL}
69 };
70 
71 EOLIAN static void
_elm_combobox_efl_ui_l10n_translation_update(Eo * obj EINA_UNUSED,Elm_Combobox_Data * sd)72 _elm_combobox_efl_ui_l10n_translation_update(Eo *obj EINA_UNUSED, Elm_Combobox_Data *sd)
73 {
74    efl_ui_l10n_translation_update(efl_super(obj, MY_CLASS));
75    efl_ui_l10n_translation_update(sd->genlist);
76    efl_ui_l10n_translation_update(sd->entry);
77 
78    if (sd->hover)
79      efl_ui_l10n_translation_update(sd->hover);
80 }
81 
82 EOLIAN static Eina_Error
_elm_combobox_efl_ui_widget_theme_apply(Eo * obj,Elm_Combobox_Data * sd)83 _elm_combobox_efl_ui_widget_theme_apply(Eo *obj, Elm_Combobox_Data *sd)
84 {
85    const char *style;
86    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
87    Eina_Bool mirrored;
88    char buf[128];
89 
90    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_ERROR_GENERIC);
91 
92    style = eina_stringshare_add(elm_widget_style_get(obj));
93 
94    snprintf(buf, sizeof(buf), "combobox_vertical/%s", style);
95 
96    /* combobox's style has no extra bit for orientation but could have... */
97    eina_stringshare_replace(&(wd->style), buf);
98 
99    int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
100    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
101 
102    eina_stringshare_replace(&(wd->style), style);
103 
104    mirrored = efl_ui_mirrored_get(obj);
105 
106    if (sd->hover)
107      {
108         efl_ui_mirrored_set(sd->hover, mirrored);
109         elm_widget_style_set(sd->hover, buf);
110      }
111 
112    efl_ui_mirrored_set(sd->genlist, mirrored);
113    efl_ui_mirrored_set(sd->entry, mirrored);
114 
115    elm_widget_style_set(sd->genlist, buf);
116    elm_widget_style_set(sd->entry, buf);
117 
118    eina_stringshare_del(style);
119 
120    return int_ret;
121 }
122 
123 static void
_on_hover_clicked(void * data,Evas_Object * obj,void * event_info EINA_UNUSED)124 _on_hover_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
125 {
126    const char *dismissstr;
127 
128    dismissstr = elm_layout_data_get(obj, "dismiss");
129 
130    if (!dismissstr || strcmp(dismissstr, "on"))
131      elm_combobox_hover_end(data); // for backward compatibility
132 }
133 
134 static void
_hover_end_finished(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)135 _hover_end_finished(void *data,
136                     Evas_Object *obj EINA_UNUSED,
137                     const char *emission EINA_UNUSED,
138                     const char *source EINA_UNUSED)
139 {
140    const char *dismissstr;
141    ELM_COMBOBOX_DATA_GET(data, sd);
142    dismissstr = elm_layout_data_get(sd->hover, "dismiss");
143    if (dismissstr && !strcmp(dismissstr, "on"))
144      {
145         sd->expanded = EINA_FALSE;
146         evas_object_hide(sd->hover);
147         efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_DISMISSED, NULL);
148      }
149 }
150 
151 static void
count_items_genlist(void * data)152 count_items_genlist(void *data)
153 {
154    ELM_COMBOBOX_DATA_GET(data, sd);
155    Eina_Iterator *filter_iter;
156    int count = 0;
157    Elm_Object_Item *item;
158 
159    filter_iter = elm_genlist_filter_iterator_new(sd->genlist);
160    if (!filter_iter) return;
161    EINA_ITERATOR_FOREACH(filter_iter, item)
162      if (item) count++;
163    sd->count = count;
164    eina_iterator_free(filter_iter);
165 }
166 
167 static void
_item_realized(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)168 _item_realized(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
169 {
170    _table_resize(data);
171 }
172 
173 static void
_table_resize(void * data)174 _table_resize(void *data)
175 {
176    ELM_COMBOBOX_DATA_GET(data, sd);
177    if (sd->count > 0)
178      {
179         int hover_parent_w, hover_parent_h, obj_h, obj_w, obj_y, win_y_offset;
180         int current_height, h;
181         Eina_List *realized;
182 
183         sd->item = elm_genlist_first_item_get(sd->genlist);
184 
185         if (!(realized = elm_genlist_realized_items_get(sd->genlist)))
186           {
187              //nothing realized and wait until at least one item is realized
188              h = 1;
189              evas_object_smart_callback_add(sd->genlist, "realized", _item_realized, data);
190           }
191         else
192           {
193              // take the first, and update according to that
194              evas_object_geometry_get(elm_object_item_track(eina_list_data_get(realized)), NULL, NULL,
195                                       NULL, &h);
196              eina_list_free(realized);
197           }
198 
199         sd->item_height = h;
200         evas_object_geometry_get(sd->entry, NULL, NULL, &obj_w, NULL);
201         evas_object_geometry_get(data, NULL, &obj_y, NULL, &obj_h);
202         evas_object_geometry_get(sd->hover_parent, NULL, NULL, &hover_parent_w,
203                                  &hover_parent_h);
204         current_height = sd->item_height * sd->count;
205         sd->best_location = elm_hover_best_content_location_get(sd->hover,
206                                                        ELM_HOVER_AXIS_VERTICAL);
207         if (sd->best_location && !strcmp(sd->best_location , "bottom"))
208           win_y_offset = hover_parent_h - obj_y - obj_h;
209         else win_y_offset = obj_y;
210 
211         if (current_height < win_y_offset)
212           evas_object_size_hint_min_set(sd->spacer, obj_w, current_height);
213         else evas_object_size_hint_min_set(sd->spacer, obj_w, win_y_offset);
214      }
215 }
216 
217 static void
_activate(Evas_Object * obj)218 _activate(Evas_Object *obj)
219 {
220    ELM_COMBOBOX_DATA_GET(obj, sd);
221    if (elm_widget_disabled_get(obj)) return;
222 
223    if (sd->expanded)
224      {
225         elm_combobox_hover_end(obj);
226         return;
227      }
228 
229    sd->expanded = EINA_TRUE;
230 
231    count_items_genlist(obj);
232 
233    if (sd->count <= 0) return;
234 
235    _table_resize(obj);
236    elm_object_part_content_set(sd->hover, sd->best_location, sd->tbl);
237    evas_object_show(sd->genlist);
238    elm_genlist_item_selected_set(sd->item, EINA_TRUE);
239    evas_object_show(sd->hover);
240    efl_event_callback_legacy_call(obj, ELM_COMBOBOX_EVENT_EXPANDED, NULL);
241 }
242 
243 static void
_on_item_selected(void * data,Evas_Object * obj EINA_UNUSED,void * event)244 _on_item_selected(void *data , Evas_Object *obj EINA_UNUSED, void *event)
245 {
246    ELM_COMBOBOX_DATA_GET(data, sd);
247    elm_object_focus_set(sd->entry, EINA_TRUE);
248 
249    efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_ITEM_SELECTED, event);
250 }
251 
252 static void
_on_item_pressed(void * data,Evas_Object * obj EINA_UNUSED,void * event)253 _on_item_pressed(void *data , Evas_Object *obj EINA_UNUSED, void *event)
254 {
255    efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_ITEM_PRESSED, event);
256 }
257 
258 static void
_gl_filter_finished_cb(void * data,const Efl_Event * event)259 _gl_filter_finished_cb(void *data, const Efl_Event *event)
260 {
261    char buf[1024];
262    ELM_COMBOBOX_DATA_GET(data, sd);
263 
264    count_items_genlist(data);
265 
266    if (sd->first_filter)
267      {
268         sd->first_filter = EINA_FALSE;
269         return;
270      }
271 
272    efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_FILTER_DONE, event->info);
273 
274    if (sd->count > 0)
275      {
276         if (!sd->expanded) _activate(data);
277         else _table_resize(data);
278         elm_genlist_item_selected_set(sd->item, EINA_TRUE);
279      }
280    else
281      {
282         sd->expanded = EINA_FALSE;
283         elm_layout_signal_emit(sd->hover, "elm,action,hide,no_animate", "elm");
284         snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide", sd->best_location);
285         elm_layout_signal_emit(sd->hover, buf, "elm");
286         edje_object_message_signal_process(elm_layout_edje_get(sd->hover));
287      }
288 }
289 
290 static void
_on_aborted(void * data,const Efl_Event * event EINA_UNUSED)291 _on_aborted(void *data, const Efl_Event *event EINA_UNUSED)
292 {
293    ELM_COMBOBOX_DATA_GET(data, sd);
294    if (sd->expanded) elm_combobox_hover_end(data);
295 }
296 
297 static void
_on_changed(void * data,const Efl_Event * event EINA_UNUSED)298 _on_changed(void *data, const Efl_Event *event EINA_UNUSED)
299 {
300    efl_event_callback_legacy_call(data, ELM_ENTRY_EVENT_CHANGED, NULL);
301 }
302 
303 static void
_on_clicked(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)304 _on_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
305 {
306    elm_combobox_hover_begin(data);
307 }
308 
309 static Eo *
_elm_combobox_component_add(Eo * obj,Eo * parent,const Efl_Class * klass,char * style)310 _elm_combobox_component_add(Eo *obj, Eo *parent, const Efl_Class *klass, char *style)
311 {
312    Eo *component;
313 
314    if (elm_widget_is_legacy(obj))
315      {
316         component = elm_legacy_add(klass, parent,
317                        efl_ui_widget_style_set(efl_added, style));
318      }
319    else
320      {
321         component = efl_add(klass, parent,
322                        efl_ui_widget_style_set(efl_added, style));
323      }
324 
325    return component;
326 }
327 
328 EOLIAN static void
_elm_combobox_efl_canvas_group_group_add(Eo * obj,Elm_Combobox_Data * sd EINA_UNUSED)329 _elm_combobox_efl_canvas_group_group_add(Eo *obj, Elm_Combobox_Data *sd EINA_UNUSED)
330 {
331    efl_canvas_group_add(efl_super(obj, MY_CLASS));
332 
333    efl_ui_mirrored_automatic_set(obj, EINA_FALSE);
334 
335    evas_object_smart_callback_add(obj, "clicked", _on_clicked, obj);
336 
337    //What are you doing here?
338    efl_ui_widget_theme_apply(obj);
339 }
340 
341 EOLIAN static void
_elm_combobox_efl_canvas_group_group_del(Eo * obj,Elm_Combobox_Data * sd)342 _elm_combobox_efl_canvas_group_group_del(Eo *obj, Elm_Combobox_Data *sd)
343 {
344    sd->hover_parent = NULL;
345    efl_canvas_group_del(efl_super(obj, MY_CLASS));
346 }
347 
348 EOLIAN static void
_elm_combobox_efl_gfx_entity_visible_set(Eo * obj,Elm_Combobox_Data * sd,Eina_Bool vis)349 _elm_combobox_efl_gfx_entity_visible_set(Eo *obj, Elm_Combobox_Data *sd, Eina_Bool vis)
350 {
351    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
352      return;
353 
354    efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis);
355    if (vis)
356      {
357         if (sd->expanded) evas_object_show(sd->hover);
358      }
359    else
360      {
361         if (sd->hover) evas_object_hide(sd->hover);
362      }
363 }
364 
365 EOLIAN static void
_elm_combobox_efl_ui_autorepeat_autorepeat_enabled_set(const Eo * obj EINA_UNUSED,Elm_Combobox_Data * sd EINA_UNUSED,Eina_Bool enabled)366 _elm_combobox_efl_ui_autorepeat_autorepeat_enabled_set(const Eo *obj EINA_UNUSED,
367                                                        Elm_Combobox_Data *sd EINA_UNUSED,
368                                                        Eina_Bool enabled)
369 {
370    if (enabled)
371      ERR("You cannot enable autorepeat on this object");
372    efl_ui_autorepeat_enabled_set(efl_super(obj, MY_CLASS), EINA_FALSE);
373 }
374 
375 EAPI Evas_Object *
elm_combobox_add(Evas_Object * parent)376 elm_combobox_add(Evas_Object *parent)
377 {
378    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
379    return elm_legacy_add(MY_CLASS, parent);
380 }
381 
382 EOLIAN static Eo *
_elm_combobox_efl_object_constructor(Eo * obj,Elm_Combobox_Data * sd)383 _elm_combobox_efl_object_constructor(Eo *obj, Elm_Combobox_Data *sd)
384 {
385    Evas_Object *gl;
386    Evas_Object *entry;
387    char buf[128];
388 
389    obj = efl_constructor(efl_super(obj, MY_CLASS));
390 
391    sd->first_filter = EINA_TRUE;
392 
393    efl_ui_autorepeat_enabled_set(obj, EINA_FALSE);
394    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
395    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
396    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_GLASS_PANE);
397 
398    //hover-parent
399    sd->hover_parent = elm_object_top_widget_get(obj);
400 
401    snprintf(buf, sizeof(buf), "combobox_vertical/%s", elm_widget_style_get(obj));
402 
403    //hover
404    sd->hover = _elm_combobox_component_add(obj, sd->hover_parent, ELM_HOVER_CLASS, buf);
405    efl_gfx_entity_visible_set(sd->hover, EINA_FALSE);
406    evas_object_layer_set(sd->hover, EVAS_LAYER_MAX);
407    efl_ui_mirrored_automatic_set(sd->hover, EINA_FALSE);
408    elm_hover_target_set(sd->hover, obj);
409    elm_widget_sub_object_add(obj, sd->hover);
410 
411    evas_object_smart_callback_add(sd->hover, "clicked", _on_hover_clicked, obj);
412    elm_layout_signal_callback_add
413      (sd->hover, "elm,action,hide,finished", "elm", _hover_end_finished, obj);
414 
415    //table
416    sd->tbl = elm_table_add(obj);
417    evas_object_size_hint_weight_set(sd->tbl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
418    evas_object_size_hint_align_set(sd->tbl, EVAS_HINT_FILL, EVAS_HINT_FILL);
419 
420    //spacer
421    sd->spacer = evas_object_rectangle_add(evas_object_evas_get(sd->hover_parent));
422    evas_object_size_hint_weight_set(sd->spacer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
423    evas_object_size_hint_align_set(sd->spacer, EVAS_HINT_FILL, EVAS_HINT_FILL);
424    evas_object_color_set(sd->spacer, 0, 0, 0, 0);
425    elm_table_pack(sd->tbl, sd->spacer, 0, 0, 1, 1);
426 
427    // This is the genlist object that will take over the genlist call
428    sd->genlist = gl = _elm_combobox_component_add(obj, obj, ELM_GENLIST_CLASS, buf);
429    elm_genlist_filter_set(gl, NULL);
430    efl_ui_mirrored_automatic_set(gl, EINA_FALSE);
431    efl_ui_mirrored_set(gl, efl_ui_mirrored_get(obj));
432    evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
433    evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
434    evas_object_smart_callback_add(gl, "selected", _on_item_selected, obj);
435    evas_object_smart_callback_add(gl, "pressed", _on_item_pressed, obj);
436    efl_event_callback_add(gl, ELM_GENLIST_EVENT_FILTER_DONE, _gl_filter_finished_cb, obj);
437    elm_genlist_homogeneous_set(gl, EINA_TRUE);
438    elm_genlist_mode_set(gl, ELM_LIST_COMPRESS);
439    elm_table_pack(sd->tbl, gl, 0, 0, 1, 1);
440 
441    // This is the entry object that will take over the entry call
442    sd->entry = entry = _elm_combobox_component_add(obj, obj, ELM_ENTRY_CLASS, buf);
443    efl_ui_mirrored_automatic_set(entry, EINA_FALSE);
444    efl_ui_mirrored_set(entry, efl_ui_mirrored_get(obj));
445    elm_scroller_policy_set(entry, ELM_SCROLLER_POLICY_OFF,
446                            ELM_SCROLLER_POLICY_OFF);
447    elm_entry_scrollable_set(entry, EINA_TRUE);
448    elm_entry_single_line_set(entry, EINA_TRUE);
449    efl_event_callback_add(entry, ELM_ENTRY_EVENT_CHANGED_USER, _on_changed, obj);
450    efl_event_callback_add(entry, ELM_ENTRY_EVENT_ABORTED, _on_aborted, obj);
451    evas_object_show(entry);
452 
453    elm_object_part_content_set(obj, "elm.swallow.content", entry);
454 
455    efl_composite_attach(obj, gl);
456    efl_composite_attach(obj, entry);
457 
458    return obj;
459 }
460 
461 EOLIAN static void
_elm_combobox_hover_begin(Eo * obj,Elm_Combobox_Data * sd)462 _elm_combobox_hover_begin(Eo *obj, Elm_Combobox_Data *sd)
463 {
464    if (!sd->hover) return;
465    elm_object_focus_set(sd->entry, EINA_TRUE);
466 
467    _activate(obj);
468 }
469 
470 EOLIAN static void
_elm_combobox_hover_end(Eo * obj,Elm_Combobox_Data * sd)471 _elm_combobox_hover_end(Eo *obj, Elm_Combobox_Data *sd)
472 {
473    const char *dismissstr;
474    if (!sd->hover) return;
475    dismissstr = elm_layout_data_get(sd->hover, "dismiss");
476 
477    if (dismissstr && !strcmp(dismissstr, "on"))
478      elm_hover_dismiss(sd->hover);
479    else
480      {
481         sd->expanded = EINA_FALSE;
482         evas_object_hide(sd->hover);
483         efl_event_callback_legacy_call(obj, ELM_COMBOBOX_EVENT_DISMISSED, NULL);
484      } // for backward compatibility
485 }
486 
487 EOLIAN static Eina_Bool
_elm_combobox_expanded_get(const Eo * obj EINA_UNUSED,Elm_Combobox_Data * sd)488 _elm_combobox_expanded_get(const Eo *obj EINA_UNUSED, Elm_Combobox_Data *sd)
489 {
490    return sd->expanded;
491 }
492 
493 static Eina_Bool
_key_action_move(Evas_Object * obj,const char * params)494 _key_action_move(Evas_Object *obj, const char *params)
495 {
496    ELM_COMBOBOX_DATA_GET(obj, sd);
497    Elm_Object_Item *it = NULL;
498    const char *dir = params;
499    if (!sd->hover) return EINA_FALSE;
500 
501    if (!strcmp(dir, "up"))
502      {
503         it = sd->item;
504         it = elm_genlist_item_prev_get(it);
505         if (!it) sd->item = elm_genlist_last_item_get(sd->genlist);
506         else sd->item = it;
507         elm_genlist_item_selected_set(sd->item, EINA_TRUE);
508      }
509    else if (!strcmp(dir, "down"))
510      {
511         it = sd->item;
512         it = elm_genlist_item_next_get(it);
513         if (!it) sd->item = elm_genlist_first_item_get(sd->genlist);
514         else sd->item = it;
515         elm_genlist_item_selected_set(sd->item, EINA_TRUE);
516      }
517    else return EINA_FALSE;
518    return EINA_TRUE;
519 }
520 
521 static Eina_Bool
_key_action_activate(Evas_Object * obj,const char * params EINA_UNUSED)522 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
523 {
524    ELM_COMBOBOX_DATA_GET(obj, sd);
525    if (!sd->hover) return EINA_FALSE;
526    if (!sd->expanded)
527      elm_combobox_hover_begin(obj);
528    else
529      {
530         evas_object_smart_callback_call(sd->genlist, "pressed", sd->item);
531         elm_entry_cursor_end_set(sd->entry);
532      }
533    return EINA_TRUE;
534 }
535 
536 static void
_elm_combobox_class_constructor(Efl_Class * klass)537 _elm_combobox_class_constructor(Efl_Class *klass)
538 {
539    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
540 }
541 
542 EOLIAN const Efl_Access_Action_Data *
_elm_combobox_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Elm_Combobox_Data * pd EINA_UNUSED)543 _elm_combobox_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED,
544                                                                 Elm_Combobox_Data *pd
545                                                                 EINA_UNUSED)
546 {
547    static Efl_Access_Action_Data atspi_actions[] = {
548       {"activate", "activate", "return", _key_action_activate},
549       {"move,up", "move", "up", _key_action_move},
550       {"move,down", "move", "down", _key_action_move},
551       {NULL, NULL, NULL, NULL}
552    };
553    return &atspi_actions[0];
554 }
555 
556 EOLIAN void
_elm_combobox_elm_genlist_filter_set(Eo * obj EINA_UNUSED,Elm_Combobox_Data * pd,void * key)557 _elm_combobox_elm_genlist_filter_set(Eo *obj EINA_UNUSED, Elm_Combobox_Data *pd, void *key)
558 {
559    pd->first_filter = EINA_FALSE;
560 
561    elm_obj_genlist_filter_set(pd->genlist, key);
562 }
563 
564 // FIXME: Combobox part API is badly defined. Efl.Part should be reimplemented
565 // properly, but this will be tricky: how to set "guide" on the "entry" part?
566 void
_elm_combobox_part_text_set(Eo * obj,const char * part,const char * label)567 _elm_combobox_part_text_set(Eo *obj, const char * part, const char *label)
568 {
569    Elm_Combobox_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
570    if (!pd) return;
571    elm_object_part_text_set(pd->entry, part, label);
572 }
573 
574 const char *
_elm_combobox_part_text_get(const Eo * obj,const char * part)575 _elm_combobox_part_text_get(const Eo *obj, const char *part)
576 {
577    Elm_Combobox_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
578    if (!pd) return NULL;
579    return elm_object_part_text_get(pd->entry, part);
580 }
581 
582 EOLIAN static void
_elm_combobox_efl_gfx_entity_size_set(Eo * obj,Elm_Combobox_Data * pd,Eina_Size2D sz)583 _elm_combobox_efl_gfx_entity_size_set(Eo *obj, Elm_Combobox_Data *pd, Eina_Size2D sz)
584 {
585    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
586      return;
587 
588    if (pd->count > 0) _table_resize(obj);
589    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz);
590 }
591 
592 /* Internal EO APIs and hidden overrides */
593 
594 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(elm_combobox, Elm_Combobox_Data)
595 
596 EOAPI EFL_FUNC_BODY_CONST(elm_obj_combobox_expanded_get, Eina_Bool, 0);
597 EOAPI EFL_VOID_FUNC_BODY(elm_obj_combobox_hover_begin);
598 EOAPI EFL_VOID_FUNC_BODY(elm_obj_combobox_hover_end);
599 
600 static Eina_Bool
_elm_combobox_class_initializer(Efl_Class * klass)601 _elm_combobox_class_initializer(Efl_Class *klass)
602 {
603    EFL_OPS_DEFINE(ops,
604       EFL_OBJECT_OP_FUNC(elm_obj_combobox_expanded_get, _elm_combobox_expanded_get),
605       EFL_OBJECT_OP_FUNC(elm_obj_combobox_hover_begin, _elm_combobox_hover_begin),
606       EFL_OBJECT_OP_FUNC(elm_obj_combobox_hover_end, _elm_combobox_hover_end),
607       EFL_OBJECT_OP_FUNC(efl_constructor, _elm_combobox_efl_object_constructor),
608       EFL_OBJECT_OP_FUNC(efl_gfx_entity_visible_set, _elm_combobox_efl_gfx_entity_visible_set),
609       EFL_OBJECT_OP_FUNC(efl_gfx_entity_size_set, _elm_combobox_efl_gfx_entity_size_set),
610       EFL_OBJECT_OP_FUNC(efl_ui_widget_theme_apply, _elm_combobox_efl_ui_widget_theme_apply),
611       EFL_OBJECT_OP_FUNC(efl_ui_l10n_translation_update, _elm_combobox_efl_ui_l10n_translation_update),
612       EFL_OBJECT_OP_FUNC(efl_ui_widget_input_event_handler, _elm_combobox_efl_ui_widget_widget_input_event_handler),
613       EFL_OBJECT_OP_FUNC(efl_ui_autorepeat_enabled_set, _elm_combobox_efl_ui_autorepeat_autorepeat_enabled_set),
614       EFL_OBJECT_OP_FUNC(elm_obj_genlist_filter_set, _elm_combobox_elm_genlist_filter_set),
615       EFL_OBJECT_OP_FUNC(efl_access_widget_action_elm_actions_get, _elm_combobox_efl_access_widget_action_elm_actions_get),
616       EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_combobox)
617    );
618 
619    return efl_class_functions_set(klass, &ops, NULL);
620 }
621 
622 static const Efl_Class_Description _elm_combobox_class_desc = {
623    EO_VERSION,
624    "Elm.Combobox",
625    EFL_CLASS_TYPE_REGULAR,
626    sizeof(Elm_Combobox_Data),
627    _elm_combobox_class_initializer,
628    _elm_combobox_class_constructor,
629    NULL
630 };
631 
632 EFL_DEFINE_CLASS(elm_combobox_class_get, &_elm_combobox_class_desc, EFL_UI_BUTTON_CLASS, EFL_ACCESS_WIDGET_ACTION_MIXIN, ELM_ENTRY_CLASS, ELM_GENLIST_CLASS, ELM_HOVER_CLASS, EFL_UI_LEGACY_INTERFACE, NULL);
633 
634 EAPI Eina_Bool
elm_combobox_expanded_get(const Elm_Combobox * obj)635 elm_combobox_expanded_get(const Elm_Combobox *obj)
636 {
637    return elm_obj_combobox_expanded_get(obj);
638 }
639 
640 EAPI void
elm_combobox_hover_begin(Elm_Combobox * obj)641 elm_combobox_hover_begin(Elm_Combobox *obj)
642 {
643    elm_obj_combobox_hover_begin(obj);
644 }
645 
646 EAPI void
elm_combobox_hover_end(Elm_Combobox * obj)647 elm_combobox_hover_end(Elm_Combobox *obj)
648 {
649    elm_obj_combobox_hover_end(obj);
650 }
651