move elementary to trunk base. out of TMP/st.
[framework/uifw/elementary.git] / src / lib / elm_label.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Label Label
6  *
7  * Display text, with simple html-like markup. The theme of course
8  * can invent new markup tags and style them any way it likes
9  */
10
11 typedef struct _Widget_Data Widget_Data;
12
13 struct _Widget_Data
14 {
15    Evas_Object *lbl;
16    Evas_Object *bg;
17    const char *label;
18    Ecore_Job *deferred_recalc_job;
19    double slide_duration;
20    Evas_Coord lastw;
21    Evas_Coord wrap_w;
22    Evas_Coord wrap_h;
23    Eina_Bool linewrap : 1;
24    Eina_Bool changed : 1;
25    Eina_Bool bgcolor : 1;
26    Eina_Bool ellipsis : 1;
27    Eina_Bool slidingmode : 1;
28    Eina_Bool slidingellipsis : 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 int _get_value_in_key_string(const char *oldstring, const char *key, char **value);
36 static int _strbuf_key_value_replace(Eina_Strbuf *srcbuf, const char *key, const char *value, int deleteflag);
37 static int _stringshare_key_value_replace(const char **srcstring, const char *key, const char *value, int deleteflag);
38 static int _is_width_over(Evas_Object *obj, Eina_Bool multiline);
39 static void _ellipsis_label_to_width(Evas_Object *obj, Eina_Bool multiline);
40 static void _label_sliding_change(Evas_Object *obj);
41
42 static void
43 _elm_win_recalc_job(void *data)
44 {
45    Widget_Data *wd = elm_widget_data_get(data);
46    Evas_Coord minw = -1, minh = -1, maxh = -1;
47    Evas_Coord resw, resh, minminw;
48    if (!wd) return;
49    wd->deferred_recalc_job = NULL;
50    evas_object_geometry_get(wd->lbl, NULL, NULL, &resw, &resh);
51    resh = 0;
52    edje_object_size_min_restricted_calc(wd->lbl, &minw, &minh, 0, 0);
53    minminw = minw;
54    if (wd->wrap_w >= resw) 
55      {
56         resw = wd->wrap_w;
57         edje_object_size_min_restricted_calc(wd->lbl, &minw, &minh, resw, 0);
58         evas_object_size_hint_min_set(data, minw, minh);
59      }
60    else
61      {
62         if (wd->wrap_w > minminw) minminw = wd->wrap_w;
63         edje_object_size_min_restricted_calc(wd->lbl, &minw, &minh, resw, 0);
64         evas_object_size_hint_min_set(data, minminw, minh);
65      }
66
67    if ((wd->ellipsis) && (wd->linewrap) && (wd->wrap_h > 0) && 
68        (_is_width_over(data, 1) == 1))
69      _ellipsis_label_to_width(data, 1);
70
71    maxh = minh;
72    evas_object_size_hint_max_set(data, -1, maxh);
73 }
74
75 static void
76 _del_hook(Evas_Object *obj)
77 {
78    Widget_Data *wd = elm_widget_data_get(obj);
79    if (!wd) return;
80    if (wd->deferred_recalc_job) ecore_job_del(wd->deferred_recalc_job);
81    if (wd->label) eina_stringshare_del(wd->label);
82    if (wd->bg) evas_object_del(wd->bg);
83    free(wd);
84 }
85
86 static void
87 _theme_change(Evas_Object *obj)
88 {
89    Widget_Data *wd = elm_widget_data_get(obj);
90    if (!wd) return;
91
92    if (wd->linewrap)
93      {
94         if (wd->ellipsis)
95           _elm_theme_object_set(obj, wd->lbl, "label", "base_wrap_ellipsis", 
96                                 elm_widget_style_get(obj));
97         else
98           _elm_theme_object_set(obj, wd->lbl, "label", "base_wrap", 
99                                 elm_widget_style_get(obj));
100      }
101    else
102      _elm_theme_object_set(obj, wd->lbl, "label", "base", 
103                            elm_widget_style_get(obj));
104 }
105
106 static void
107 _theme_hook(Evas_Object *obj)
108 {
109    Widget_Data *wd = elm_widget_data_get(obj);
110    if (!wd) return;
111    _theme_change(obj);
112    edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
113    edje_object_scale_set(wd->lbl, elm_widget_scale_get(obj) * 
114                          _elm_config->scale);
115    _label_sliding_change(obj);
116    _sizing_eval(obj);
117 }
118
119 static void
120 _sizing_eval(Evas_Object *obj)
121 {
122    Widget_Data *wd = elm_widget_data_get(obj);
123    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
124    Evas_Coord resw, resh;
125    if (!wd) return;
126    if (wd->linewrap)
127      {
128         evas_object_geometry_get(wd->lbl, NULL, NULL, &resw, &resh);
129         if ((resw == wd->lastw) && (!wd->changed)) return;
130         wd->changed = EINA_FALSE;
131         wd->lastw = resw;
132         _elm_win_recalc_job(obj);
133 // FIXME: works ok. but NOT for genlist. what should genlist do?        
134 //        if (wd->deferred_recalc_job) ecore_job_del(wd->deferred_recalc_job);
135 //        wd->deferred_recalc_job = ecore_job_add(_elm_win_recalc_job, obj);
136      }
137    else
138      {
139         evas_object_geometry_get(wd->lbl, NULL, NULL, &resw, &resh);
140         edje_object_size_min_calc(wd->lbl, &minw, &minh);
141         if (wd->wrap_w > 0 && minw > wd->wrap_w) minw = wd->wrap_w;
142         evas_object_size_hint_min_set(obj, minw, minh);
143         maxh = minh;
144         evas_object_size_hint_max_set(obj, maxw, maxh);
145         if ((wd->ellipsis) && (_is_width_over(obj, 0) == 1))
146            _ellipsis_label_to_width(obj, 0);
147      }
148 }
149
150 static void 
151 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
152 {
153    Widget_Data *wd = elm_widget_data_get(data);
154    if (!wd) return;
155    if (wd->linewrap) _sizing_eval(data);
156 }
157
158 static int
159 _get_value_in_key_string(const char *oldstring, const char *key, char **value)
160 {
161    char *curlocater, *starttag, *endtag;
162    int firstindex = 0, foundflag = -1;
163    
164    curlocater = strstr(oldstring, key);
165    if (curlocater)
166      {
167         int key_len = strlen(key);
168         starttag = curlocater;
169         endtag = curlocater + key_len;
170         if ((!endtag) || (*endtag != '='))
171           {
172              foundflag = 0;
173              return -1;
174           }
175         firstindex = abs(oldstring - curlocater);
176         firstindex += key_len + 1; // strlen("key") + strlen("=")
177         *value = (char *)oldstring + firstindex;
178         
179         while (oldstring != starttag)
180           {
181              if (*starttag == '>')
182                {
183                   foundflag = 0;
184                   break;
185                }
186              if (*starttag == '<') 
187                break;
188              else 
189                starttag--;
190              if (!starttag) break;
191           }
192         
193         while (endtag)
194           {
195              if (*endtag == '<')
196                {
197                   foundflag = 0;
198                   break;
199                }
200              if (*endtag == '>') 
201                break;
202              else 
203                endtag++;
204              if (!endtag) break;
205           }
206         
207         if ((foundflag) && (*starttag == '<') && (*endtag == '>'))
208           foundflag = 1;
209         else 
210           foundflag = 0;
211      }
212    else
213      {
214         foundflag = 0;
215      }
216    
217    if (foundflag == 1) return 0;
218    
219    return -1;
220 }
221
222
223 static int
224 _strbuf_key_value_replace(Eina_Strbuf *srcbuf, const char *key, const char *value, int deleteflag)
225 {
226    const char *srcstring = NULL;
227    Eina_Strbuf *repbuf = NULL, *diffbuf = NULL;
228    char *curlocater, *replocater;
229    char *starttag, *endtag;
230    int tagtxtlen = 0, insertflag = 0;
231    
232    srcstring = eina_strbuf_string_get(srcbuf);
233    curlocater = strstr(srcstring, key);
234    
235    if (!curlocater)
236      insertflag = 1;
237    else
238      {
239         int key_len = strlen(key);
240         do 
241           {
242              starttag = strchr(srcstring, '<');
243              endtag = strchr(srcstring, '>');
244              tagtxtlen = endtag - starttag;
245              if (tagtxtlen <= 0) tagtxtlen = 0;
246              if ((starttag < curlocater) && (curlocater < endtag)) break;
247              if ((endtag) && ((endtag + 1)))
248                srcstring = endtag + 1;
249              else
250                break;
251           } while (strlen(srcstring) > 1);
252         
253         if ((starttag) && (endtag) && (tagtxtlen > key_len))
254           {
255              repbuf = eina_strbuf_new();
256              diffbuf = eina_strbuf_new();
257              eina_strbuf_append_n(repbuf, starttag, tagtxtlen);
258              srcstring = eina_strbuf_string_get(repbuf);
259              curlocater = strstr(srcstring, key);
260              if (curlocater)
261                {
262                   replocater = curlocater + key_len + 1;
263                   while ((*replocater != '=') && (replocater))
264                     replocater++;
265
266                   while ((*replocater) && 
267                          (*replocater != ' ') && 
268                          (*replocater != '>'))
269                     replocater++;
270
271                   if ((replocater - curlocater) > (key_len + 1))
272                     {
273                        replocater--;
274                        eina_strbuf_append_n(diffbuf, curlocater, 
275                                             replocater-curlocater);
276                     }
277                   else
278                     insertflag = 1;
279                }
280              else
281                insertflag = 1;
282              eina_strbuf_reset(repbuf);
283           }
284         else
285           insertflag = 1; 
286      }
287    
288    if (!repbuf) repbuf = eina_strbuf_new();
289    if (!diffbuf) diffbuf = eina_strbuf_new();
290    
291    if (insertflag)
292      {
293         eina_strbuf_append_printf(repbuf, "<%s=%s>", key, value);
294         eina_strbuf_prepend(srcbuf, eina_strbuf_string_get(repbuf));
295      }
296    else
297      {
298         if (deleteflag)
299           {
300              eina_strbuf_prepend(diffbuf, "<");
301              eina_strbuf_append(diffbuf, ">");
302              eina_strbuf_replace_first(srcbuf, eina_strbuf_string_get(diffbuf), "");
303           }
304         else
305           {
306              eina_strbuf_append_printf(repbuf, "%s=%s", key, value);
307              eina_strbuf_replace_first(srcbuf, eina_strbuf_string_get(diffbuf), eina_strbuf_string_get(repbuf));
308           }
309      }
310
311    if (repbuf) eina_strbuf_free(repbuf);
312    if (diffbuf) eina_strbuf_free(diffbuf);
313   
314    return 0;           
315 }
316
317 static int
318 _stringshare_key_value_replace(const char **srcstring, const char *key, const char *value, int deleteflag)
319 {
320    Eina_Strbuf *sharebuf = NULL;   
321    
322    sharebuf = eina_strbuf_new();
323    eina_strbuf_append(sharebuf, *srcstring);
324    _strbuf_key_value_replace(sharebuf, key, value, deleteflag);
325    eina_stringshare_del(*srcstring);
326    *srcstring = eina_stringshare_add(eina_strbuf_string_get(sharebuf));
327    eina_strbuf_free(sharebuf);
328
329    return 0;
330 }
331
332 static int
333 _is_width_over(Evas_Object *obj, Eina_Bool multiline)
334 {
335    Evas_Coord x, y, w, h;
336    Evas_Coord vx, vy, vw, vh;
337    Widget_Data *wd = elm_widget_data_get(obj);
338    if (!wd) return 0;
339    const char *ellipsis_string = "...";
340    int mincount = sizeof(ellipsis_string) - 1;
341    char *plaintxt;
342    int plainlen = 0;
343
344    plaintxt = _elm_util_mkup_to_text(edje_object_part_text_get(wd->lbl, "elm.text"));
345    if (plaintxt)
346      {
347         plainlen = strlen(plaintxt);
348         free(plaintxt);
349      }
350    // too short to ellipsis
351    if (plainlen <= mincount) return 0;
352
353    edje_object_part_geometry_get(wd->lbl, "elm.text", &x, &y, &w, &h);
354    evas_object_geometry_get(obj, &vx, &vy, &vw, &vh);
355
356    if (!multiline) // single line
357      {
358         // skip if too early to check widget size
359         if ((w < 0) && (h < 0)) return 0;
360         // if string fits at widget
361         if ((x >= 0) && (y >= 0))
362           {
363              if ((wd->wrap_w > 0) && (wd->wrap_w < w))
364                {
365                   Evas_Coord minw, minh;
366                   
367                   edje_object_size_min_calc(wd->lbl, &minw, &minh);
368                   if (minw < wd->wrap_w) return 0; // min insufficient
369                   else return 1;
370                }
371              else return 0;
372           }
373         if ((0 < wd->wrap_w) && (w > wd->wrap_w)) return 1;
374      }
375    else // multiline
376      {
377         if (((x >= 0) || (y >= 0)) && (h > wd->wrap_h)) return 1;
378      }
379    
380    return 0;
381 }
382
383 static void
384 _ellipsis_fontsize_set(Evas_Object *obj, int fontsize)
385 {
386    Widget_Data *wd = elm_widget_data_get(obj);
387    if (!wd) return;
388
389    Eina_Strbuf *fontbuf = NULL;
390    Eina_Strbuf *txtbuf = NULL;
391    txtbuf = eina_strbuf_new();
392    fontbuf = eina_strbuf_new();
393    eina_strbuf_append(txtbuf, edje_object_part_text_get(wd->lbl, "elm.text"));
394    eina_strbuf_append_printf(fontbuf, "%d", fontsize);
395    _strbuf_key_value_replace(txtbuf, "font_size", eina_strbuf_string_get(fontbuf), 0);
396    edje_object_part_text_set(wd->lbl, "elm.text", eina_strbuf_string_get(txtbuf));
397    eina_strbuf_free(fontbuf);
398    eina_strbuf_free(txtbuf);
399 }
400
401 static Eina_Bool
402 _ellipsis_cut_chars_to_widget(Evas_Object *obj)
403 {
404    Widget_Data *wd = elm_widget_data_get(obj);
405    if (!wd) return EINA_FALSE;
406    const char *ellipsis_string = "...";
407    int mincount = sizeof(ellipsis_string) - 1; 
408    Evas_Coord w, h;
409    Evas_Textblock_Cursor *tc1, *tc2;
410    char *cutstr, *elstr;
411    int limitw = 0;
412    int lencutstr = 0;
413    int i = 0;
414
415    edje_object_part_geometry_get(wd->lbl, "elm.text", NULL, NULL, &w, &h);
416    if (w <= 0) return EINA_FALSE;
417    tc1 = evas_object_textblock_cursor_new((Evas_Object *)edje_object_part_object_get(wd->lbl, "elm.text"));
418    tc2 = evas_object_textblock_cursor_new((Evas_Object *)edje_object_part_object_get(wd->lbl, "elm.text"));
419
420    if ((wd->wrap_w > 0) && (wd->wrap_w < w)) limitw = wd->wrap_w;
421    else limitw = w;
422    evas_textblock_cursor_pos_set(tc1, 0);
423    evas_textblock_cursor_char_coord_set(tc2, limitw, 0);
424
425    // if too small to cut,(is it bug? or any other reasons?)
426    // then fallback to one step mode
427    if (evas_textblock_cursor_pos_get(tc2) < mincount)
428      {
429         Evas_Coord cx, cy, cw, ch;
430         int eolpos = evas_textblock_cursor_paragraph_text_length_get(tc1);
431         
432         for (i = eolpos; i > mincount; i--)
433           {
434              evas_textblock_cursor_pos_set(tc2, i);
435              evas_textblock_cursor_char_geometry_get(tc2, &cx, &cy, &cw, &ch);
436              if (cx <= limitw) break;
437           }
438
439         if (evas_textblock_cursor_pos_get(tc2) < mincount)
440           {
441              evas_textblock_cursor_free(tc1);
442              evas_textblock_cursor_free(tc2);
443              return EINA_FALSE;
444           }
445      }
446
447    for (i = 0; i <= mincount; i++) evas_textblock_cursor_char_prev(tc2);
448    cutstr = evas_textblock_cursor_range_text_get(tc1, tc2, EVAS_TEXTBLOCK_TEXT_PLAIN);
449    if (!cutstr) return EINA_FALSE;
450    
451    lencutstr = strlen(cutstr);
452    elstr = alloca(sizeof(char) * (lencutstr + mincount + 1));
453    strcpy(elstr, cutstr);
454    free(cutstr);
455    strcat(elstr, ellipsis_string);
456    edje_object_part_text_set(wd->lbl, "elm.text", elstr);
457
458    evas_textblock_cursor_free(tc1);
459    evas_textblock_cursor_free(tc2);
460    
461    return EINA_TRUE;
462 }
463
464 static Eina_Bool
465 _ellipsis_cut_lines_to_widget(Evas_Object *obj)
466 {
467    Widget_Data *wd = elm_widget_data_get(obj);
468    if (!wd) return EINA_FALSE;
469    const char *ellipsis_string = "...";
470    int mincount = sizeof(ellipsis_string) - 1; 
471    Evas_Coord w, h;
472    Evas_Textblock_Cursor *tc1, *tc2;
473    int linenum = 0, cutline = 0;
474    double lineheight = 0.0;
475    char *cutstr, *elstr;
476    int lencutstr = 0;
477    int limith = 0;
478    int i;
479
480    edje_object_part_geometry_get(wd->lbl, "elm.text", NULL, NULL, &w, &h);
481
482    tc1 = evas_object_textblock_cursor_new((Evas_Object *)edje_object_part_object_get(wd->lbl, "elm.text"));
483    tc2 = evas_object_textblock_cursor_new((Evas_Object *)edje_object_part_object_get(wd->lbl, "elm.text"));
484    // goto last paragraph
485    while (evas_textblock_cursor_paragraph_next(tc2) == EINA_TRUE);
486    
487    evas_textblock_cursor_paragraph_last(tc2);
488    // get total linenumber
489    linenum = evas_textblock_cursor_line_geometry_get(tc2, NULL, NULL, NULL, NULL);
490    lineheight = (double)h / (double)linenum;
491    if ((wd->wrap_h > 0) && (wd->wrap_h < h)) limith = wd->wrap_h;
492    else limith = h;
493    cutline = limith / lineheight;
494    if (cutline < 1) cutline = 1;
495    
496    evas_textblock_cursor_pos_set(tc1, 0);
497    evas_textblock_cursor_line_set(tc2, cutline - 1);
498    evas_textblock_cursor_line_char_last(tc2);
499    for (i = 0; i <= mincount; i++) evas_textblock_cursor_char_prev(tc2);
500    cutstr = evas_textblock_cursor_range_text_get(tc1, tc2, EVAS_TEXTBLOCK_TEXT_PLAIN);
501    if (!cutstr) return EINA_FALSE;
502    
503    lencutstr = strlen(cutstr);
504    elstr = alloca(sizeof(char) * (lencutstr + mincount + 1));
505    strcpy(elstr, cutstr);
506    free(cutstr);
507    strcat(elstr, ellipsis_string);
508    edje_object_part_text_set(wd->lbl, "elm.text", elstr);
509
510    evas_textblock_cursor_free(tc1);
511    evas_textblock_cursor_free(tc2);
512
513    return EINA_TRUE;
514 }
515
516 static void
517 _ellipsis_label_to_width(Evas_Object *obj, Eina_Bool multiline)
518 {
519    Widget_Data *wd = elm_widget_data_get(obj);
520    if (!wd) return;
521    int cur_fontsize = 0;
522    char *kvalue;
523    const char *minfont, *deffont, *maxfont;
524    int minfontsize, maxfontsize;
525
526    minfont = edje_object_data_get(wd->lbl, "min_font_size");
527    if (minfont) minfontsize = atoi(minfont);
528    else minfontsize = 1;
529    maxfont = edje_object_data_get(wd->lbl, "max_font_size");
530    if (maxfont) maxfontsize = atoi(maxfont);
531    else maxfontsize = 1;
532    deffont = edje_object_data_get(wd->lbl, "default_font_size");
533    if (deffont) cur_fontsize = atoi(deffont);
534    else cur_fontsize = 1;
535    if (minfontsize > maxfontsize || cur_fontsize == 1) return;  // theme is not ready for ellipsis
536    if (eina_stringshare_strlen(wd->label) <= 0) return;
537    
538    if (_get_value_in_key_string(wd->label, "font_size", &kvalue) == 0)
539      {
540         if (kvalue != NULL) cur_fontsize = atoi(kvalue);
541      }
542    
543    while (_is_width_over(obj, multiline))
544      {
545         if (cur_fontsize > minfontsize)
546           {
547              cur_fontsize -= 3;
548              if (cur_fontsize < minfontsize) cur_fontsize = minfontsize;
549              _ellipsis_fontsize_set(obj, cur_fontsize);
550           }
551         else
552           {
553              if (!multiline) // single line
554                {
555                   _ellipsis_cut_chars_to_widget(obj);
556                   break;
557                }
558              else // multiline
559                {
560                   _ellipsis_cut_lines_to_widget(obj);
561                   break;
562                }
563           }
564      }
565 }
566
567 static void
568 _label_sliding_change(Evas_Object *obj)
569 {
570    Widget_Data *wd = elm_widget_data_get(obj);
571    if (!wd) return;
572    char *plaintxt;
573    int plainlen = 0;
574    
575    // dosen't support multiline sliding effect
576    if (wd->linewrap)
577      { 
578         wd->slidingmode = EINA_FALSE;
579         return;
580      }
581
582    plaintxt = _elm_util_mkup_to_text(edje_object_part_text_get(wd->lbl, "elm.text"));
583    if (plaintxt != NULL)
584      {
585         plainlen = strlen(plaintxt);
586         free(plaintxt);
587      }
588    // too short to slide label
589    if (plainlen < 1)
590      {
591         wd->slidingmode = EINA_TRUE;
592         return;
593      }
594
595    if (wd->slidingmode)
596      {
597         Edje_Message_Float_Set *msg = alloca(sizeof(Edje_Message_Float_Set) + (sizeof(double)));
598         
599         if (wd->ellipsis)
600           {
601              wd->slidingellipsis = EINA_TRUE;
602              elm_label_ellipsis_set(obj, EINA_FALSE);
603           }
604         
605         msg->count = 1;
606         msg->val[0] = wd->slide_duration;
607
608         edje_object_message_send(wd->lbl, EDJE_MESSAGE_FLOAT_SET, 0, msg);
609         edje_object_signal_emit(wd->lbl, "elm,state,slide,start", "elm");
610      }
611    else
612      {
613         edje_object_signal_emit(wd->lbl, "elm,state,slide,stop", "elm");
614         if (wd->slidingellipsis)
615           {
616              wd->slidingellipsis = EINA_FALSE;
617              elm_label_ellipsis_set(obj, EINA_TRUE);
618           }
619      }
620 }
621
622 /**
623  * Add a new label to the parent
624  *
625  * @param parent The parent object
626  * @return The new object or NULL if it cannot be created
627  *
628  * @ingroup Label
629  */
630 EAPI Evas_Object *
631 elm_label_add(Evas_Object *parent)
632 {
633    Evas_Object *obj;
634    Evas *e;
635    Widget_Data *wd;
636
637    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
638
639    wd = ELM_NEW(Widget_Data);
640    e = evas_object_evas_get(parent);
641    if (!e) return NULL;
642    wd->bgcolor = EINA_FALSE;
643    wd->bg = evas_object_rectangle_add(e);
644    evas_object_color_set(wd->bg, 0, 0, 0, 0);
645    obj = elm_widget_add(e);
646    ELM_SET_WIDTYPE(widtype, "label");
647    elm_widget_type_set(obj, "label");
648    elm_widget_sub_object_add(parent, obj);
649    elm_widget_data_set(obj, wd);
650    elm_widget_del_hook_set(obj, _del_hook);
651    elm_widget_theme_hook_set(obj, _theme_hook);
652    elm_widget_can_focus_set(obj, EINA_FALSE);
653
654    wd->linewrap = EINA_FALSE;
655    wd->ellipsis = EINA_FALSE;
656    wd->slidingmode = EINA_FALSE;
657    wd->slidingellipsis = EINA_FALSE;
658    wd->wrap_w = 0;
659    wd->wrap_h = 0;
660    wd->slide_duration = 10;
661
662    wd->lbl = edje_object_add(e);
663    _elm_theme_object_set(obj, wd->lbl, "label", "base", "default");
664    wd->label = eina_stringshare_add("<br>");
665    edje_object_part_text_set(wd->lbl, "elm.text", "<br>");
666    elm_widget_resize_object_set(obj, wd->lbl);
667    
668    evas_object_event_callback_add(wd->lbl, EVAS_CALLBACK_RESIZE, _resize, obj);
669    
670    wd->changed = 1;
671    _sizing_eval(obj);
672    return obj;
673 }
674
675 /**
676  * Set the label on the label object
677  *
678  * @param obj The label object
679  * @param label The label will be used on the label object
680  *
681  * @ingroup Label
682  */
683 EAPI void
684 elm_label_label_set(Evas_Object *obj, const char *label)
685 {
686    ELM_CHECK_WIDTYPE(obj, widtype);
687    Widget_Data *wd = elm_widget_data_get(obj);
688    if (!wd) return;
689    if (!label) label = "";
690    eina_stringshare_replace(&wd->label, label);
691    edje_object_part_text_set(wd->lbl, "elm.text", label);
692    wd->changed = 1;
693    _sizing_eval(obj);
694 }
695
696 /**
697  * Get the label used on the label object
698  *
699  * @param obj The label object
700  * @return The string inside the label
701  * @ingroup Label
702  */
703 EAPI const char *
704 elm_label_label_get(const Evas_Object *obj)
705 {
706    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
707    Widget_Data *wd = elm_widget_data_get(obj);
708    if (!wd) return NULL;
709    return wd->label;
710 }
711
712 /**
713  * Set the wrapping behavior of the label
714  *
715  * @param obj The label object
716  * @param wrap To wrap text or not
717  * @ingroup Label
718  */
719 EAPI void
720 elm_label_line_wrap_set(Evas_Object *obj, Eina_Bool wrap)
721 {
722    ELM_CHECK_WIDTYPE(obj, widtype);
723    Widget_Data *wd = elm_widget_data_get(obj);
724    if (!wd) return;
725    const char *t;
726    if (wd->linewrap == wrap) return;
727    wd->linewrap = wrap;
728    t = eina_stringshare_add(elm_label_label_get(obj));
729    _theme_change(obj);
730    elm_label_label_set(obj, t);
731    eina_stringshare_del(t);
732    wd->changed = 1;
733    _sizing_eval(obj);
734 }
735
736 /**
737  * Get the wrapping behavior of the label
738  *
739  * @param obj The label object
740  * @return To wrap text or not
741  * @ingroup Label
742  */
743 EAPI Eina_Bool
744 elm_label_line_wrap_get(const Evas_Object *obj)
745 {
746    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
747    Widget_Data *wd = elm_widget_data_get(obj);
748    if (!wd) return EINA_FALSE;
749    return wd->linewrap;
750 }
751
752 /**
753  * Set wrap width of the label
754  *
755  * @param obj The label object
756  * @param w The wrap width in pixels at a minimum where words need to wrap
757  * @ingroup Label
758  */
759 EAPI void
760 elm_label_wrap_width_set(Evas_Object *obj, Evas_Coord w)
761 {
762    ELM_CHECK_WIDTYPE(obj, widtype);
763    Widget_Data *wd = elm_widget_data_get(obj);
764    if (!wd) return;
765    if (w < 0) w = 0;
766    if (wd->wrap_w == w) return;
767    if (wd->ellipsis) edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
768    wd->wrap_w = w;
769    _sizing_eval(obj);
770 }
771
772 /**
773  * get wrap width of the label
774  *
775  * @param obj The label object
776  * @return The wrap width in pixels at a minimum where words need to wrap
777  * @ingroup Label
778  */
779 EAPI Evas_Coord
780 elm_label_wrap_width_get(const Evas_Object *obj)
781 {
782    ELM_CHECK_WIDTYPE(obj, widtype) 0;
783    Widget_Data *wd = elm_widget_data_get(obj);
784    if (!wd) return 0;
785    return wd->wrap_w;
786 }
787
788 /**
789  * Set wrap height of the label
790  *
791  * @param obj The label object
792  * @param w The wrap width in pixels at a minimum where words need to wrap
793  * @ingroup Label
794  */
795 EAPI void
796 elm_label_wrap_height_set(Evas_Object *obj,
797                           Evas_Coord   h)
798 {
799    ELM_CHECK_WIDTYPE(obj, widtype);
800    Widget_Data *wd = elm_widget_data_get(obj);
801    if (!wd) return;
802    if (h < 0) h = 0;
803    if (wd->wrap_h == h) return;
804    if (wd->ellipsis) edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
805    wd->wrap_h = h;
806    _sizing_eval(obj);
807 }
808
809 /**
810  * get wrap width of the label
811  *
812  * @param obj The label object
813  * @return The wrap height in pixels at a minimum where words need to wrap
814  * @ingroup Label
815  */
816 EAPI Evas_Coord
817 elm_label_wrap_height_get(const Evas_Object *obj)
818 {
819    ELM_CHECK_WIDTYPE(obj, widtype) 0;
820    Widget_Data *wd = elm_widget_data_get(obj);
821    if (!wd) return 0;
822    return wd->wrap_h;
823 }
824
825 /**
826  * Set the font size on the label object.
827  * 
828  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
829  * "big", "medium", "small" - or better name them by use:
830  * "title", "footnote", "quote" etc.
831  *
832  * @param obj The label object
833  * @param size font size
834  *
835  * @ingroup Label
836  */
837 EAPI void
838 elm_label_fontsize_set(Evas_Object *obj, int fontsize)
839 {
840    ELM_CHECK_WIDTYPE(obj, widtype);
841    Widget_Data *wd = elm_widget_data_get(obj);
842    Eina_Strbuf *fontbuf = NULL;
843    int len, removeflag = 0;
844
845    if (!wd) return;
846    _elm_dangerous_call_check(__FUNCTION__);
847    len = strlen(wd->label);
848    if (len <= 0) return;
849    fontbuf = eina_strbuf_new();
850    eina_strbuf_append_printf(fontbuf, "%d", fontsize);
851
852    if (fontsize == 0) removeflag = 1;  // remove fontsize tag
853
854    if (_stringshare_key_value_replace(&wd->label, "font_size", eina_strbuf_string_get(fontbuf), removeflag) == 0)
855      {
856         edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
857         wd->changed = 1;
858         _sizing_eval(obj);
859      }
860    eina_strbuf_free(fontbuf);
861 }
862
863 /**
864  * Set the text align on the label object
865  *
866  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
867  * "big", "medium", "small" - or better name them by use:
868  * "title", "footnote", "quote" etc.
869  *
870  * @param obj The label object
871  * @param align align mode ("left", "center", "right")
872  *
873  * @ingroup Label
874  */
875 EAPI void
876 elm_label_text_align_set(Evas_Object *obj, const char *alignmode)
877 {
878    ELM_CHECK_WIDTYPE(obj, widtype);
879    Widget_Data *wd = elm_widget_data_get(obj);
880    int len;
881
882    if (!wd) return;
883    _elm_dangerous_call_check(__FUNCTION__);
884    len = strlen(wd->label);
885    if (len <= 0) return;
886
887    if (_stringshare_key_value_replace(&wd->label, "align", alignmode, 0) == 0)
888      edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
889
890    wd->changed = 1;
891    _sizing_eval(obj);
892 }
893
894 /**
895  * Set the text color on the label object
896  *
897  * @param obj The label object
898  * @param r Red property background color of The label object
899  * @param g Green property background color of The label object
900  * @param b Blue property background color of The label object
901  * @param a Alpha property background color of The label object
902  *
903  * @ingroup Label
904  */
905 EAPI void
906 elm_label_text_color_set(Evas_Object *obj,
907                          unsigned int r,
908                          unsigned int g,
909                          unsigned int b,
910                          unsigned int a)
911 {
912    ELM_CHECK_WIDTYPE(obj, widtype);
913    Widget_Data *wd = elm_widget_data_get(obj);
914    Eina_Strbuf *colorbuf = NULL;
915    int len;
916
917    if (!wd) return;
918    _elm_dangerous_call_check(__FUNCTION__);
919    len = strlen(wd->label);
920    if (len <= 0) return;
921    colorbuf = eina_strbuf_new();
922    eina_strbuf_append_printf(colorbuf, "#%02X%02X%02X%02X", r, g, b, a);
923
924    if (_stringshare_key_value_replace(&wd->label, "color", eina_strbuf_string_get(colorbuf), 0) == 0)
925      {
926         edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
927         wd->changed = 1;
928         _sizing_eval(obj);
929      }
930    eina_strbuf_free(colorbuf);
931 }
932
933 /**
934  * Set background color of the label
935  *
936  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
937  * "big", "medium", "small" - or better name them by use:
938  * "title", "footnote", "quote" etc.
939  *
940  * @param obj The label object
941  * @param r Red property background color of The label object 
942  * @param g Green property background color of The label object 
943  * @param b Blue property background color of The label object 
944  * @param a Alpha property background alpha of The label object 
945  *
946  * @ingroup Label
947  */
948 EAPI void
949 elm_label_background_color_set(Evas_Object *obj,
950                                unsigned int r,
951                                unsigned int g,
952                                unsigned int b,
953                                unsigned int a)
954 {
955    ELM_CHECK_WIDTYPE(obj, widtype);
956    Widget_Data *wd = elm_widget_data_get(obj);
957    if (!wd) return;
958    evas_object_color_set(wd->bg, r, g, b, a);
959
960    if (!wd) return;
961    _elm_dangerous_call_check(__FUNCTION__);
962    if (wd->bgcolor == EINA_FALSE)
963      {
964         wd->bgcolor = 1;
965         edje_object_part_swallow(wd->lbl, "label.swallow.background", wd->bg);
966      }
967 }
968
969 /**
970  * Set the ellipsis behavior of the label
971  *
972  * @param obj The label object
973  * @param ellipsis To ellipsis text or not
974  * @ingroup Label
975  */
976 EAPI void
977 elm_label_ellipsis_set(Evas_Object *obj, Eina_Bool ellipsis)
978 {
979    ELM_CHECK_WIDTYPE(obj, widtype);
980    Widget_Data *wd = elm_widget_data_get(obj);
981    if (!wd) return;
982    if (wd->ellipsis == ellipsis) return;
983    wd->ellipsis = ellipsis;
984    if (wd->linewrap) _theme_change(obj);
985    edje_object_part_text_set(wd->lbl, "elm.text", wd->label);
986    wd->changed = 1;
987    _sizing_eval(obj);
988 }
989
990 /**
991  * Set the text slide of the label
992  *
993  * @param obj The label object
994  * @param slide To start slide or stop
995  * @ingroup Label
996  */
997 EAPI void
998 elm_label_slide_set(Evas_Object *obj,
999                     Eina_Bool    slide)
1000 {
1001    ELM_CHECK_WIDTYPE(obj, widtype);
1002    Widget_Data *wd = elm_widget_data_get(obj);
1003    if (!wd) return;
1004
1005    if (wd->slidingmode == slide) return;
1006    wd->slidingmode = slide;
1007    _label_sliding_change(obj);
1008    wd->changed = 1;
1009    _sizing_eval(obj);
1010 }
1011
1012 /**
1013  * get the text slide mode of the label
1014  *
1015  * @param obj The label object
1016  * @return slide slide mode value
1017  * @ingroup Label
1018  */
1019 EAPI Eina_Bool
1020 elm_label_slide_get(Evas_Object *obj)
1021 {
1022    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1023    Widget_Data *wd = elm_widget_data_get(obj);
1024    if (!wd) return EINA_FALSE;
1025    return wd->slidingmode;
1026 }
1027
1028 /**
1029  * set the slide duration(speed) of the label
1030  *
1031  * @param obj The label object
1032  * @return The duration time in moving text from slide begin position to slide end position
1033  * @ingroup Label
1034  */
1035 EAPI void
1036 elm_label_slide_duration_set(Evas_Object *obj, double duration)
1037 {
1038    ELM_CHECK_WIDTYPE(obj, widtype);
1039    Widget_Data *wd = elm_widget_data_get(obj);
1040    Edje_Message_Float_Set *msg = alloca(sizeof(Edje_Message_Float_Set) + (sizeof(double)));
1041
1042    if (!wd) return;
1043    wd->slide_duration = duration;
1044    msg->count = 1;
1045    msg->val[0] = wd->slide_duration;
1046    edje_object_message_send(wd->lbl, EDJE_MESSAGE_FLOAT_SET, 0, msg);
1047 }
1048
1049 /**
1050  * get the slide duration(speed) of the label
1051  *
1052  * @param obj The label object
1053  * @return The duration time in moving text from slide begin position to slide end position
1054  * @ingroup Label
1055  */
1056 EAPI double
1057 elm_label_slide_duration_get(Evas_Object *obj)
1058 {
1059    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
1060    Widget_Data *wd = elm_widget_data_get(obj);
1061    if (!wd) return 0;
1062    return wd->slide_duration;
1063 }
1064