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