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