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