[Merge conflict resolved]
[framework/uifw/elementary.git] / src / lib / elm_searchbar.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 #include <Elementary.h>
5 #include "elm_priv.h"
6
7 /**
8  * @defgroup Searchbar Searchbar
9  * @ingroup Elementary
10  *
11  * This is Searchbar.
12  * It can contain a simple entry and button object.
13  */
14
15 typedef struct _Widget_Data Widget_Data;
16
17 struct _Widget_Data
18 {
19    Evas_Object *base, *ef, *cancel_btn;
20    Eina_Bool cancel_btn_ani_flag;
21    Eina_Bool cancel_btn_show_mode;
22    Eina_Bool boundary_mode;
23    Ecore_Idler *idler;
24 };
25
26 static const char *widtype = NULL;
27 static void _del_hook(Evas_Object *obj);
28 static void _theme_hook(Evas_Object *obj);
29 static void _on_focus_hook(void *data, Evas_Object *obj);
30 static void _sizing_eval(Evas_Object *obj);
31 static void _clicked(void *data, Evas_Object *obj,
32                      const char *emission, const char *source);
33 static void _changed(void *data, Evas_Object *obj, void *event_info);
34 static void _cancel_clicked(void *data, Evas_Object *obj, void *event_info);
35
36 static void _del_hook(Evas_Object *obj)
37 {
38    Widget_Data *wd = elm_widget_data_get(obj);
39
40    if (!wd) return;
41    if (wd->idler) ecore_idler_del(wd->idler);
42
43    free(wd);
44 }
45
46 static void _theme_hook(Evas_Object *obj)
47 {
48    Widget_Data *wd = elm_widget_data_get(obj);
49    char buf[4096];
50
51    if (!wd) return;
52
53    _elm_theme_object_set(obj, wd->base, "searchbar", "base", elm_widget_style_get(obj));
54
55    if (wd->ef)
56      edje_object_part_swallow(wd->base, "search_textfield", wd->ef);
57    if (wd->cancel_btn)
58      edje_object_part_swallow(wd->base, "button_cancel", wd->cancel_btn);
59
60    snprintf(buf, sizeof(buf), "searchbar/%s", elm_widget_style_get(obj));
61    elm_object_style_set(wd->ef, buf);
62
63    snprintf(buf, sizeof(buf), "searchbar/%s", elm_widget_style_get(obj));
64    elm_object_style_set(wd->cancel_btn, buf);
65
66    edje_object_scale_set(wd->cancel_btn, elm_widget_scale_get(obj) * _elm_config->scale);
67    _sizing_eval(obj);
68 }
69
70 static void
71 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
72 {
73    Widget_Data *wd = elm_widget_data_get(obj);
74    if (!wd || !wd->base)
75       return;
76    if (elm_widget_focus_get(obj))
77      {
78         /*FIXME: Sending clicked signal to focus editfield once open source is merged
79          * remove the below call
80          */
81         elm_object_signal_emit(wd->ef, "clicked", "elm");
82         if (wd->cancel_btn_show_mode)
83           {
84              if (wd->cancel_btn_ani_flag) edje_object_signal_emit(wd->base, "CANCELIN", "PROG");
85              else edje_object_signal_emit(wd->base, "CANCELSHOW", "PROG");
86           }
87      }
88    else
89      {
90         if (wd->cancel_btn_ani_flag) edje_object_signal_emit(wd->base, "CANCELOUT", "PROG");
91         else edje_object_signal_emit(wd->base, "CANCELHIDE", "PROG");
92      }
93 }
94
95 static void _sizing_eval(Evas_Object *obj)
96 {
97    Widget_Data *wd = elm_widget_data_get(obj);
98    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
99
100    if (!wd) return;
101    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
102    edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
103    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
104    evas_object_size_hint_min_set(obj, minw, minh);
105    evas_object_size_hint_max_set(obj, maxw, maxh);
106 }
107
108 static void _clicked(void *data, Evas_Object *obj __UNUSED__,
109                      const char *emission __UNUSED__, const char *source __UNUSED__)
110 {
111    evas_object_smart_callback_call(data, "clicked", NULL);
112 }
113
114 static Eina_Bool _delay_changed(void *data)
115 {
116    Widget_Data *wd = elm_widget_data_get(data);
117
118    if (!wd) return ECORE_CALLBACK_CANCEL;
119
120    evas_object_smart_callback_call(data, "delay-changed", NULL);
121    wd->idler = NULL;
122    return ECORE_CALLBACK_CANCEL;
123 }
124
125 static void _changed(void *data, Evas_Object *obj __UNUSED__,
126                      void *event_info __UNUSED__)
127 {
128    Widget_Data *wd = elm_widget_data_get(data);
129
130    if (!wd) return;
131    if (!wd->idler)
132       wd->idler = ecore_idler_add(_delay_changed, data);
133 }
134
135 static void _cancel_clicked(void *data, Evas_Object *obj __UNUSED__,
136                             void *event_info __UNUSED__)
137 {
138    Widget_Data *wd = elm_widget_data_get(data);
139    if (!wd) return;
140
141    const char* text;
142    text = elm_entry_entry_get(elm_editfield_entry_get(wd->ef));
143    if (text != NULL && strlen(text) > 0)
144      elm_entry_entry_set(elm_editfield_entry_get(wd->ef), NULL);
145    elm_object_unfocus(data);
146    evas_object_smart_callback_call(data, "cancel,clicked", NULL);
147 }
148
149 static void
150 _searchsymbol_clicked(void *data, Evas_Object *obj __UNUSED__,
151                       const char *emission __UNUSED__,
152                       const char *source __UNUSED__)
153 {
154    Widget_Data *wd = elm_widget_data_get(data);
155
156    if (!wd) return;
157    evas_object_smart_callback_call(data, "searchsymbol,clicked", NULL);
158 }
159
160 static void
161 _elm_searchbar_text_set(Evas_Object *obj, const char *item, const char *text)
162 {
163    ELM_CHECK_WIDTYPE(obj, widtype);
164    Widget_Data *wd = elm_widget_data_get(obj);
165    if (item && strcmp(item, "default")) return;
166    if (!wd) return;
167    elm_entry_entry_set(elm_editfield_entry_get(wd->ef), text);
168 }
169
170 static const char *
171 _elm_searchbar_text_get(const Evas_Object *obj, const char *item)
172 {
173    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
174    Widget_Data *wd = elm_widget_data_get(obj);
175    if (item && strcmp(item, "default")) return NULL;
176    if (!wd) return NULL;
177    return elm_entry_entry_get(elm_editfield_entry_get(wd->ef));
178 }
179
180
181 /**
182  * Add a new searchbar to the parent
183  * @param parent The parent object
184  * @return The new object or NULL if it cannot be created
185  *
186  * @ingroup Searchbar
187  */
188 EAPI Evas_Object *elm_searchbar_add(Evas_Object *parent)
189 {
190    Evas_Object *obj;
191    Evas *e;
192    Widget_Data *wd;
193    char buf[4096];
194
195    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
196
197    ELM_SET_WIDTYPE(widtype, "searchbar");
198    elm_widget_type_set(obj, "searchbar");
199    elm_widget_sub_object_add(parent, obj);
200    elm_widget_data_set(obj, wd);
201    elm_widget_del_hook_set(obj, _del_hook);
202    elm_widget_theme_hook_set(obj, _theme_hook);
203    elm_widget_on_focus_hook_set( obj, _on_focus_hook, NULL);
204    elm_widget_can_focus_set(obj, EINA_TRUE);
205    elm_widget_text_set_hook_set(obj, _elm_searchbar_text_set);
206    elm_widget_text_get_hook_set(obj, _elm_searchbar_text_get);
207
208    wd->base = edje_object_add(e);
209    _elm_theme_object_set(obj, wd->base, "searchbar", "base", "default");
210    elm_widget_resize_object_set(obj, wd->base);
211
212    // Add Entry
213    wd->ef = elm_editfield_add(obj);
214    elm_object_style_set(wd->ef, "searchbar/default");
215
216    edje_object_part_swallow(wd->base, "search_textfield", wd->ef);
217    elm_editfield_guide_text_set(wd->ef, E_("Search"));
218    elm_editfield_entry_single_line_set(wd->ef, EINA_TRUE);
219    elm_editfield_eraser_set(wd->ef, EINA_TRUE);
220    evas_object_smart_callback_add(elm_editfield_entry_get(wd->ef), "changed", _changed, obj);
221    edje_object_signal_callback_add(wd->base, "mouse,clicked,1", "*", _clicked, obj);
222    edje_object_signal_callback_add(wd->base, "elm,action,click", "", _searchsymbol_clicked, obj);
223
224    // Add Button
225    wd->cancel_btn = elm_button_add(obj);
226    edje_object_part_swallow(wd->base, "button_cancel", wd->cancel_btn);
227    snprintf(buf, sizeof(buf), "searchbar/%s", elm_widget_style_get(obj));
228    elm_object_style_set(wd->cancel_btn, buf);
229    elm_object_text_set(wd->cancel_btn, E_("Cancel"));
230    evas_object_smart_callback_add(wd->cancel_btn, "clicked", _cancel_clicked, obj);
231
232    wd->cancel_btn_ani_flag = EINA_FALSE;
233    wd->cancel_btn_show_mode = EINA_TRUE;
234    wd->boundary_mode = EINA_TRUE;
235
236    _sizing_eval(obj);
237
238    return obj;
239 }
240
241 /**
242  * set the text of entry
243  *
244  * @param obj The searchbar object
245  * @return void
246  *
247  * @ingroup Searchbar
248  */
249 EAPI void elm_searchbar_text_set(Evas_Object *obj, const char *entry)
250 {
251    _elm_searchbar_text_set(obj, NULL, entry);
252 }
253
254 /**
255  * get the text of entry
256  *
257  * @param obj The searchbar object
258  * @return string pointer of entry
259  *
260  * @ingroup Searchbar
261  */
262 EAPI const char* elm_searchbar_text_get(Evas_Object *obj)
263 {
264    return _elm_searchbar_text_get(obj, NULL);
265 }
266
267 /**
268  * get the pointer of entry
269  *
270  * @param obj The searchbar object
271  * @return the entry object
272  *
273  * @ingroup Searchbar
274  */
275 EAPI Evas_Object *elm_searchbar_entry_get(Evas_Object *obj)
276 {
277    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
278    Widget_Data *wd = elm_widget_data_get(obj);
279    if (!wd) return NULL;
280
281    return elm_editfield_entry_get(wd->ef);
282 }
283
284 /**
285  * get the pointer of editfield
286  *
287  * @param obj The searchbar object
288  * @return the editfield object
289  *
290  * @ingroup Searchbar
291  */
292 EAPI Evas_Object *elm_searchbar_editfield_get(Evas_Object *obj)
293 {
294    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
295    Widget_Data *wd = elm_widget_data_get(obj);
296    if (!wd || !wd->ef) return NULL;
297
298    return wd->ef;
299 }
300
301 /**
302  * set the cancel button animation flag
303  *
304  * @param obj The searchbar object
305  * @param cancel_btn_ani_flag The flag of animating cancen button or not
306  * @return void
307  *
308  * @ingroup Searchbar
309  */
310 EAPI void elm_searchbar_cancel_button_animation_set(Evas_Object *obj, Eina_Bool cancel_btn_ani_flag)
311 {
312    ELM_CHECK_WIDTYPE(obj, widtype);
313    Widget_Data *wd = elm_widget_data_get(obj);
314    if (!wd) return;
315
316    if (wd->cancel_btn_ani_flag == cancel_btn_ani_flag) return;
317    else wd->cancel_btn_ani_flag = cancel_btn_ani_flag;
318 }
319
320 /**
321  * set the cancel button show mode
322  *
323  * @param obj The searchbar object
324  * @param visible The flag of cancen button show or not
325  * @return void
326  *
327  * @ingroup Searchbar
328  */
329 EAPI void elm_searchbar_cancel_button_set(Evas_Object *obj, Eina_Bool visible)
330 {
331    ELM_CHECK_WIDTYPE(obj, widtype);
332    Widget_Data *wd = elm_widget_data_get(obj);
333    if (!wd) return;
334
335    if (wd->cancel_btn_show_mode == visible) return;
336    else wd->cancel_btn_show_mode = visible;
337
338    if (!visible)
339      {
340         if (wd->cancel_btn_ani_flag)
341            edje_object_signal_emit(wd->base, "CANCELOUT", "PROG");
342         else
343            edje_object_signal_emit(wd->base, "CANCELHIDE", "PROG");
344      }
345    _sizing_eval(obj);
346 }
347
348 /**
349  * clear searchbar status
350  *
351  * @param obj The searchbar object
352  * @return void
353  *
354  * @ingroup Searchbar
355  */
356 EAPI void elm_searchbar_clear(Evas_Object *obj)
357 {
358    ELM_CHECK_WIDTYPE(obj, widtype);
359    Widget_Data *wd = elm_widget_data_get(obj);
360    if (!wd) return;
361
362    if (wd->cancel_btn_show_mode)
363      {
364         if (wd->cancel_btn_ani_flag)
365            edje_object_signal_emit(wd->base, "CANCELOUT", "PROG");
366         else
367            edje_object_signal_emit(wd->base, "CANCELHIDE", "PROG");
368      }
369 //   elm_entry_entry_set(elm_editfield_entry_get(wd->ef), NULL);
370 }
371
372 /**
373  * set the searchbar boundary rect mode(with bg rect) set
374  *
375  * @param obj The searchbar object
376  * @param boundary The present flag of boundary rect or not
377  * @return void
378  *
379  * @ingroup Searchbar
380  */
381 EAPI void elm_searchbar_boundary_rect_set(Evas_Object *obj, Eina_Bool boundary)
382 {
383    ELM_CHECK_WIDTYPE(obj, widtype);
384    Widget_Data *wd = elm_widget_data_get(obj);
385    if (!wd) return;
386
387    if (wd->boundary_mode == boundary) return;
388    else wd->boundary_mode = boundary;
389
390    if (wd->boundary_mode)
391      {
392         edje_object_signal_emit(wd->base, "BDSHOW", "PROG");
393      }
394    else
395      {
396         edje_object_signal_emit(wd->base, "BDHIDE", "PROG");
397      }
398    _sizing_eval(obj);
399 }