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