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