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