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