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