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