Merge "[elm_datefield.c] warning is corrected in Datefield API."
[framework/uifw/elementary.git] / src / lib / elm_editfield.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Editfield Editfield
6  * @ingroup Elementary
7  *
8  * This is a editfield. It can contain a simple label and icon objects.
9  *
10  * Smart callbacks that you can add are:
11  *
12  * clicked - This signal is emitted when an editfield is clicked.
13  *
14  * unfocused - This signal is emitted when an editfield is unfocused.
15  *
16  */
17
18 //#define ERASER_PADDING (10)
19
20 typedef struct _Widget_Data Widget_Data;
21
22 struct _Widget_Data
23 {
24    Evas_Object *base;
25    Evas_Object *entry;
26    Evas_Object *scroller;
27    Evas_Object *ricon;
28    Evas_Object *licon;
29    const char *label;
30    const char *guide_text;
31    Eina_Bool needs_size_calc:1;
32    Eina_Bool show_guide_text:1;
33    Eina_Bool editing:1;
34    Eina_Bool single_line:1;
35    Eina_Bool eraser_show:1;
36 };
37
38 static const char *widtype = NULL;
39 static void _del_hook(Evas_Object *obj);
40 static void _theme_hook(Evas_Object *obj);
41 static void _sizing_eval(Evas_Object *obj);
42 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
43 static void _on_focus_hook(void *data, Evas_Object *obj);
44 static Eina_Bool _empty_entry(Evas_Object *entry);
45
46 static void
47 _del_hook(Evas_Object *obj)
48 {
49    Widget_Data *wd = elm_widget_data_get(obj);
50    if (!wd) return;
51    if (wd->label) eina_stringshare_del(wd->label);
52    free(wd);
53 }
54
55 static void
56 _on_focus_hook(void *data, Evas_Object *obj)
57 {
58    Widget_Data *wd = elm_widget_data_get(obj);
59    if (!wd || !wd->base)
60       return;
61    if (!elm_widget_focus_get(obj) && !(elm_widget_disabled_get(obj)) )
62      {
63         evas_object_smart_callback_call(obj, "unfocused", NULL);
64         wd->editing = EINA_FALSE;
65         edje_object_signal_emit(wd->base, "elm,state,over,show", "elm");
66         edje_object_signal_emit(wd->base, "elm,state,eraser,hidden", "elm");
67         if(_empty_entry(wd->entry))
68           {
69              if(wd->guide_text)
70                {
71                   edje_object_part_text_set(wd->base, "elm.guidetext", wd->guide_text);
72                   edje_object_signal_emit(wd->base, "elm,state,guidetext,visible", "elm");
73                   wd->show_guide_text = EINA_TRUE;
74                }
75           }
76      }
77 }
78
79 static void
80 _theme_hook(Evas_Object *obj)
81 {
82    Widget_Data *wd = elm_widget_data_get(obj);
83    if (!wd || !wd->base)
84       return;
85    _elm_theme_object_set(obj, wd->base, "editfield", "base", elm_widget_style_get(obj));
86    if(wd->single_line)
87       edje_object_part_swallow(wd->base, "elm.swallow.content", wd->scroller);
88    else
89       edje_object_part_swallow(wd->base, "elm.swallow.content", wd->entry);
90    if(!wd->editing)
91       edje_object_signal_emit(wd->base, "elm,state,over,show", "elm");
92    if(wd->show_guide_text)
93      {
94         if(_empty_entry(wd->entry))
95           {
96              if(wd->guide_text)
97                {
98                   edje_object_part_text_set(wd->base, "elm.guidetext", wd->guide_text);
99                   edje_object_signal_emit(wd->base, "elm,state,guidetext,visible", "elm");
100                }
101           }
102      }
103    if(wd->ricon)
104       edje_object_part_swallow(wd->base, "right_icon", wd->ricon);
105    if(wd->licon)
106       edje_object_part_swallow(wd->base, "left_icon", wd->licon);
107    _sizing_eval(obj);
108 }
109
110 static void
111 _changed_hook(Evas_Object *obj)
112 {
113    Widget_Data *wd = elm_widget_data_get(obj);
114    if (wd->needs_size_calc)
115      {
116         _sizing_eval(obj);
117         wd->needs_size_calc = EINA_FALSE;
118      }
119 }
120
121 static void
122 _sizing_eval(Evas_Object *obj)
123 {
124    Widget_Data *wd = elm_widget_data_get(obj);
125    Evas_Coord minw = -1, minh = -1;
126    edje_object_size_min_calc(wd->base, &minw, &minh);
127    evas_object_size_hint_min_set(obj, minw, minh);
128    evas_object_size_hint_max_set(obj, -1, -1);
129 }
130
131 static void
132 _request_sizing_eval(Evas_Object *obj)
133 {
134    Widget_Data *wd = elm_widget_data_get(obj);
135    if(!wd || !wd->base)
136       return;
137    if (wd->needs_size_calc)
138       return;
139    wd->needs_size_calc = EINA_TRUE;
140    evas_object_smart_changed(obj);
141 }
142
143 static void
144 _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info)
145 {
146    double weight_x;
147    evas_object_size_hint_weight_get(data, &weight_x, NULL);
148    if (weight_x == EVAS_HINT_EXPAND)
149       _request_sizing_eval(data);
150 }
151
152 static Eina_Bool
153 _empty_entry(Evas_Object *entry)
154 {
155    const char* text;
156    char *strip_text;
157    int len = 0;
158
159    text = elm_entry_entry_get(entry);
160    if(!text) return EINA_FALSE;
161    strip_text = elm_entry_markup_to_utf8(text);
162    if (strip_text) {
163         len = strlen(strip_text);
164         free(strip_text);
165    }
166    if(len == 0)
167       return EINA_TRUE;
168    else
169       return EINA_FALSE;
170 }
171
172 static void
173 _entry_changed_cb(void *data, Evas_Object *obj, void* event_info)
174 {
175    Evas_Object *ef_obj = (Evas_Object *)data;
176    Widget_Data *wd = elm_widget_data_get(ef_obj);
177
178    if(!wd || !wd->base) return;
179
180    if(!_empty_entry(wd->entry))
181      {
182         if(wd->eraser_show && elm_object_focus_get(obj))
183            edje_object_signal_emit(wd->base, "elm,state,eraser,show", "elm");
184         if(wd->guide_text)
185           {
186              edje_object_signal_emit(wd->base, "elm,state,guidetext,hidden", "elm");
187              wd->show_guide_text = EINA_FALSE;
188           }
189      }
190    else
191      {
192         if(wd->eraser_show)
193            edje_object_signal_emit(wd->base, "elm,state,eraser,hidden", "elm");
194      }
195 }
196
197 static void
198 _signal_mouse_clicked(void *data, Evas_Object *obj, const char *emission, const char *source)
199 {
200    Widget_Data *wd = elm_widget_data_get(data);
201    if(!wd || !wd->base) return;
202
203    if(!strcmp(source, "eraser"))
204      {
205         elm_entry_entry_set(wd->entry, "");
206         edje_object_signal_emit(wd->base, "elm,state,eraser,hidden", "elm");
207      }
208    else if(strcmp(source, "left_icon") && strcmp(source, "right_icon") && strcmp(source, "eraser"))
209      {
210         edje_object_signal_emit(wd->base, "elm,state,over,hide", "elm");
211
212         elm_object_focus(wd->entry);
213
214         if(wd->editing == EINA_FALSE)
215            elm_entry_cursor_end_set(wd->entry);
216
217         if(!(_empty_entry(wd->entry)) && (wd->eraser_show))
218            edje_object_signal_emit(wd->base, "elm,state,eraser,show", "elm");
219
220         if(wd->guide_text)
221           {
222              edje_object_signal_emit(wd->base, "elm,state,guidetext,hidden", "elm");
223              wd->show_guide_text = EINA_FALSE;
224           }
225         evas_object_smart_callback_call(data, "clicked", NULL);
226         wd->editing = EINA_TRUE;
227      }
228 }
229
230 static void
231 _resize_cb(void *data, Evas *evas, Evas_Object *obj, void *event)
232 {
233    Widget_Data *wd = elm_widget_data_get(data);
234    Evas_Coord h;
235    if (!wd || !wd->base) return;
236    evas_object_geometry_get(obj, NULL, NULL, NULL, &h);
237 }
238
239 static void
240 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
241 {
242    Widget_Data *wd = elm_widget_data_get(obj);
243    if (!wd) return;
244    edje_object_signal_emit(wd->base, emission, source);
245 }
246
247
248 /**
249  * Add a new editfield object
250  *
251  * @param parent The parent object
252  * @return The new object or NULL if it cannot be created
253  *
254  * @ingroup Editfield
255  */
256 EAPI Evas_Object *
257 elm_editfield_add(Evas_Object *parent)
258 {
259    Evas_Object *obj;
260    Evas *e;
261    Widget_Data *wd;
262
263    e = evas_object_evas_get(parent);
264    if (e == NULL)
265       return NULL;
266    wd = ELM_NEW(Widget_Data);
267    obj = elm_widget_add(e);
268    ELM_SET_WIDTYPE(widtype, "editfield");
269    elm_widget_type_set(obj, "editfield");
270    elm_widget_sub_object_add(parent, obj);
271    elm_widget_data_set(obj, wd);
272    elm_widget_del_hook_set(obj, _del_hook);
273    elm_widget_theme_hook_set(obj, _theme_hook);
274    elm_widget_changed_hook_set(obj, _changed_hook);
275    elm_widget_on_focus_hook_set( obj, _on_focus_hook, NULL );
276    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
277    elm_widget_can_focus_set(obj, EINA_TRUE);
278
279    wd->base = edje_object_add(e);
280    _elm_theme_object_set(obj, wd->base, "editfield", "base", "default");
281    elm_widget_resize_object_set(obj, wd->base);
282    edje_object_signal_callback_add(wd->base, "mouse,clicked,1", "*",
283                                    _signal_mouse_clicked, obj);
284    edje_object_signal_callback_add(wd->base, "clicked", "*",
285                                    _signal_mouse_clicked, obj);
286
287    evas_object_event_callback_add(wd->base, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
288
289    wd->editing = EINA_FALSE;
290    wd->single_line = EINA_FALSE;
291    wd->eraser_show = EINA_TRUE;
292
293    wd->entry = elm_entry_add(obj);
294    elm_object_style_set(wd->entry, "editfield");
295    evas_object_size_hint_weight_set(wd->entry, 0, EVAS_HINT_EXPAND);
296    evas_object_size_hint_align_set(wd->entry, 0, EVAS_HINT_FILL);
297    evas_object_event_callback_add(wd->entry,
298                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
299                                   _changed_size_hints, obj);
300    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->entry);
301    evas_object_smart_callback_add(wd->entry, "changed", _entry_changed_cb, obj);
302    elm_widget_sub_object_add(obj, wd->entry);
303    evas_object_show(wd->entry);
304    _sizing_eval(obj);
305
306    return obj;
307 }
308
309 /**
310  * Set the label of editfield
311  *
312  * @param obj The editfield object
313  * @param label The label text
314  *
315  * @ingroup Editfield
316  */
317 EAPI void
318 elm_editfield_label_set(Evas_Object *obj, const char *label)
319 {
320    Widget_Data *wd = elm_widget_data_get(obj);
321    ELM_CHECK_WIDTYPE(obj, widtype);
322    if (!wd || !wd->base)
323       return;
324    if (wd->label)
325       eina_stringshare_del(wd->label);
326    if (label)
327      {
328         wd->label = eina_stringshare_add(label);
329         edje_object_signal_emit(wd->base, "elm,state,text,visible", "elm");
330         edje_object_signal_emit(wd->base, "elm,state,left,icon,hide", "elm");
331      }
332    else
333      {
334         wd->label = NULL;
335         edje_object_signal_emit(wd->base, "elm,state,text,hidden", "elm");
336         edje_object_signal_emit(wd->base, "elm,state,left,icon,show", "elm");
337      }
338    edje_object_message_signal_process(wd->base);
339    edje_object_part_text_set(wd->base, "elm.text", label);
340    _sizing_eval(obj);
341 }
342
343 /**
344  * Get the label used on the editfield object
345  *
346  * @param obj The editfield object
347  * @return label text
348  *
349  * @ingroup Editfield
350  */
351 EAPI const char*
352 elm_editfield_label_get(Evas_Object *obj)
353 {
354    Widget_Data *wd = elm_widget_data_get(obj);
355    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
356    if (!wd || !wd->base)
357       return NULL;
358    return wd->label;
359 }
360
361 /**
362  * Set the guidance text used on the editfield object
363  *
364  * @param obj The editfield object
365  * @return label text
366  *
367  * @ingroup Editfield
368  */
369 EAPI void
370 elm_editfield_guide_text_set(Evas_Object *obj, const char *text)
371 {
372    Widget_Data *wd = elm_widget_data_get(obj);
373    ELM_CHECK_WIDTYPE(obj, widtype);
374    if (!wd || !wd->base)
375       return;
376    if (wd->guide_text)
377       eina_stringshare_del(wd->guide_text);
378    if (text)
379      {
380         wd->guide_text = eina_stringshare_add(text);
381         edje_object_part_text_set(wd->base, "elm.guidetext", wd->guide_text);
382         wd->show_guide_text = EINA_TRUE;
383      }
384    else
385       wd->guide_text = NULL;
386 }
387
388 /**
389  * Get the guidance text used on the editfield object
390  *
391  * @param obj The editfield object
392  * @return label text
393  *
394  * @ingroup Editfield
395  */
396 EAPI const char*
397 elm_editfield_guide_text_get(Evas_Object *obj)
398 {
399    Widget_Data *wd = elm_widget_data_get(obj);
400    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
401    if (!wd || !wd->base)
402       return NULL;
403    return wd->guide_text;
404 }
405
406 /**
407  * Get the entry of the editfield object
408  *
409  * @param obj The editfield object
410  * @return entry object
411  *
412  * @ingroup Editfield
413  */
414
415 EAPI Evas_Object *
416 elm_editfield_entry_get(Evas_Object *obj)
417 {
418    Widget_Data *wd = elm_widget_data_get(obj);
419    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
420    if (!wd)
421       return NULL;
422    return wd->entry;
423 }
424
425 /**
426  * Set the left side icon.
427  *
428  * @param obj The editfield object
429  * @param icon The icon object
430  *
431  * @ingroup Editfield
432  */
433 EAPI void
434 elm_editfield_left_icon_set(Evas_Object *obj, Evas_Object *icon)
435 {
436    Widget_Data *wd = elm_widget_data_get(obj);
437    ELM_CHECK_WIDTYPE(obj, widtype) ;
438    if (!wd || !wd->base || !icon)
439       return;
440    if ((wd->licon != icon) && (wd->licon))
441       elm_widget_sub_object_del(obj, wd->licon);
442    if (icon)
443      {
444         if (!(edje_object_part_swallow(wd->base, "left_icon", icon)))
445            return;
446         wd->licon = icon;
447         elm_widget_sub_object_add(obj, icon);
448         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
449                                        _changed_size_hints, obj);
450         edje_object_signal_emit(wd->base, "elm,state,left,icon,show", "elm");
451         edje_object_signal_emit(wd->base, "elm,state,text,hidden", "elm");
452         _sizing_eval(obj);
453      }
454    return;
455 }
456
457 /**
458  * Get the left side icon
459  *
460  * @param obj The editfield object
461  * @return icon object
462  *
463  * @ingroup Editfield
464  */
465 EAPI Evas_Object *
466 elm_editfield_left_icon_get(Evas_Object *obj)
467 {
468    Widget_Data *wd = elm_widget_data_get(obj);
469    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
470    if (!wd || !wd->base || !wd->licon)
471       return NULL;
472    return wd->licon;
473 }
474
475 /**
476  * Set the right side icon.
477  *
478  * @param obj The editfield object
479  * @param icon The icon object
480  *
481  * @ingroup Editfield
482  */
483 EAPI void
484 elm_editfield_right_icon_set(Evas_Object *obj, Evas_Object *icon)
485 {
486    Widget_Data *wd = elm_widget_data_get(obj);
487    ELM_CHECK_WIDTYPE(obj, widtype) ;
488    if (!wd || !wd->base || !icon)
489       return;
490    if ((wd->ricon != icon) && (wd->ricon))
491       elm_widget_sub_object_del(obj, wd->ricon);
492    if (icon)
493      {
494         if ( !(edje_object_part_swallow(wd->base, "right_icon", icon)) )
495            return;
496         wd->ricon = icon;
497         elm_widget_sub_object_add(obj, icon);
498         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
499                                        _changed_size_hints, obj);
500         edje_object_signal_emit(wd->base, "elm,state,right,icon,show", "elm");
501         _sizing_eval(obj);
502      }
503    return;
504 }
505
506 /**
507  * Get the right side icon
508  *
509  * @param obj The editfield object
510  * @return icon object
511  *
512  * @ingroup Editfield
513  */
514 EAPI Evas_Object *
515 elm_editfield_right_icon_get(Evas_Object *obj)
516 {
517    Widget_Data *wd = elm_widget_data_get(obj);
518    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
519    if (!wd || !wd->base || !wd->ricon)
520       return NULL;
521    return wd->ricon;
522 }
523
524 /**
525  * Set entry object style as single-line or multi-line.
526  *
527  * @param obj The editfield object
528  * @param single_line 1 if single-line , 0 if multi-line
529  *
530  * @ingroup Editfield
531  */
532 EAPI void
533 elm_editfield_entry_single_line_set(Evas_Object *obj, Eina_Bool single_line)
534 {
535    Widget_Data *wd = elm_widget_data_get(obj);
536    Evas_Object *entry;
537    ELM_CHECK_WIDTYPE(obj, widtype);
538    if (!wd || !wd->base || wd->single_line == single_line)
539       return;
540    wd->single_line = single_line;
541    elm_entry_single_line_set(wd->entry, single_line);
542    if(single_line)
543      {
544         if(!wd->scroller)
545           {
546              wd->scroller = elm_scroller_add(obj);
547              elm_scroller_bounce_set(wd->scroller, 0, 0);
548              elm_scroller_policy_set(wd->scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
549              elm_widget_sub_object_add(obj, wd->scroller);
550              elm_scroller_content_min_limit(wd->scroller, 0, 1);
551           }
552         edje_object_part_unswallow(wd->base, wd->entry);
553         edje_object_part_swallow(wd->base, "elm.swallow.content", wd->scroller);
554         evas_object_size_hint_weight_set(wd->entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
555         evas_object_size_hint_align_set(wd->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
556
557         elm_scroller_content_set(wd->scroller, wd->entry);
558      }
559    else
560      {
561         entry = elm_entry_add(obj);
562         elm_object_style_set(entry, "editfield");
563         evas_object_size_hint_weight_set(entry, 0, EVAS_HINT_EXPAND);
564         evas_object_size_hint_align_set(entry, 0, EVAS_HINT_FILL);
565         evas_object_event_callback_add(entry,
566                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
567                                        _changed_size_hints, obj);
568         edje_object_part_swallow(wd->base, "elm.swallow.content", entry);
569         evas_object_smart_callback_add(entry, "changed", _entry_changed_cb, obj);
570         elm_widget_sub_object_add(obj, entry);
571         elm_entry_entry_set(entry, elm_entry_entry_get(wd->entry));
572         if(wd->scroller)
573            edje_object_part_unswallow(wd->base, wd->scroller);
574         evas_object_del(wd->entry);
575         wd->entry = entry;
576         edje_object_part_swallow(wd->base, "elm.swallow.content", wd->entry);
577      }
578 }
579
580 /**
581  * Get the current entry object style(single-line or multi-line)
582  *
583  * @param obj The editfield object
584  * @return 1 if single-line , 0 if multi-line
585  *
586  * @ingroup Editfield
587  */
588 EAPI Eina_Bool
589 elm_editfield_entry_single_line_get(Evas_Object *obj)
590 {
591    Widget_Data *wd = elm_widget_data_get(obj);
592    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
593    if (!wd || !wd->base)
594       return EINA_FALSE;
595    return wd->single_line;
596 }
597
598 /**
599  * Set enable user to clean all of text.
600  *
601  * @param obj The editfield object
602  * @param visible If true, the eraser is visible and user can clean all of text by using eraser.
603  * If false, the eraser is invisible.
604  *
605  * @ingroup Editfield
606  */
607 EAPI void
608 elm_editfield_eraser_set(Evas_Object *obj, Eina_Bool visible)
609 {
610    Widget_Data *wd = elm_widget_data_get(obj);
611    ELM_CHECK_WIDTYPE(obj, widtype);
612    if (!wd || !wd->base)
613       return;
614
615    wd->eraser_show = visible;
616
617    if (!visible)
618       edje_object_signal_emit(wd->base, "elm,state,eraser,hidden", "elm");
619
620    return;
621 }
622
623 /**
624  * Get the current state of erase (visible/invisible)
625  *
626  * @param obj The editfield object
627  * @return 1 if visible, 0 if invisible
628  *
629  * @ingroup Editfield
630  */
631 EAPI Eina_Bool
632 elm_editfield_eraser_get(Evas_Object *obj)
633 {
634    Widget_Data *wd = elm_widget_data_get(obj);
635    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
636    if (!wd || !wd->base)
637       return EINA_FALSE;
638    return wd->eraser_show;
639 }
640
641 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/