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