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