Merge branch 'master' into svn_merge
[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, 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    while (_is_width_over(obj))
472      {
473         if (cur_fontsize > minfontsize)
474           {
475              cur_fontsize -= 3;
476              if (cur_fontsize < minfontsize) cur_fontsize = minfontsize;
477              _ellipsis_fontsize_set(obj, cur_fontsize);
478           }
479         else
480           {
481              break;
482           }
483      }
484 }
485
486 static void
487 _label_sliding_change(Evas_Object *obj)
488 {
489    Widget_Data *wd = elm_widget_data_get(obj);
490    if (!wd) return;
491    char *plaintxt;
492    int plainlen = 0;
493
494    // dosen't support multiline sliding effect
495    if (wd->linewrap)
496      {
497         wd->slidingmode = EINA_FALSE;
498         return;
499      }
500
501    plaintxt = _elm_util_mkup_to_text(edje_object_part_text_get(wd->lbl, "elm.text"));
502    if (plaintxt != NULL)
503      {
504         plainlen = strlen(plaintxt);
505         free(plaintxt);
506      }
507    // too short to slide label
508    if (plainlen < 1)
509      {
510         wd->slidingmode = EINA_TRUE;
511         return;
512      }
513
514    if (wd->slidingmode)
515      {
516         Edje_Message_Float_Set *msg = alloca(sizeof(Edje_Message_Float_Set) + (sizeof(double)));
517
518         if (wd->ellipsis)
519           {
520              wd->slidingellipsis = EINA_TRUE;
521              elm_label_ellipsis_set(obj, EINA_FALSE);
522           }
523
524         msg->count = 1;
525         msg->val[0] = wd->slide_duration;
526
527         edje_object_message_send(wd->lbl, EDJE_MESSAGE_FLOAT_SET, 0, msg);
528         edje_object_signal_emit(wd->lbl, "elm,state,slide,start", "elm");
529      }
530    else
531      {
532         edje_object_signal_emit(wd->lbl, "elm,state,slide,stop", "elm");
533         if (wd->slidingellipsis)
534           {
535              wd->slidingellipsis = EINA_FALSE;
536              elm_label_ellipsis_set(obj, EINA_TRUE);
537           }
538      }
539 }
540
541 static void
542 _elm_label_label_set(Evas_Object *obj, const char *item, const char *label)
543 {
544    ELM_CHECK_WIDTYPE(obj, widtype);
545    Widget_Data *wd = elm_widget_data_get(obj);
546    if (!wd) return;
547    if (item && strcmp(item, "default")) return;
548    if (!label) label = "";
549    eina_stringshare_replace(&wd->label, label);
550    edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
551    edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
552    wd->changed = 1;
553    _sizing_eval(obj);
554 }
555
556 static const char *
557 _elm_label_label_get(const Evas_Object *obj, const char *item)
558 {
559    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
560    Widget_Data *wd = elm_widget_data_get(obj);
561    if (item && strcmp(item, "default")) return NULL;
562    if (!wd) return NULL;
563    return wd->label;
564 }
565
566 /**
567  * Add a new label to the parent
568  *
569  * @param parent The parent object
570  * @return The new object or NULL if it cannot be created
571  *
572  * @ingroup Label
573  */
574 EAPI Evas_Object *
575 elm_label_add(Evas_Object *parent)
576 {
577    Evas_Object *obj;
578    Evas *e;
579    Widget_Data *wd;
580
581    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
582
583    ELM_SET_WIDTYPE(widtype, "label");
584    elm_widget_type_set(obj, "label");
585    elm_widget_sub_object_add(parent, obj);
586    elm_widget_data_set(obj, wd);
587    elm_widget_del_hook_set(obj, _del_hook);
588    elm_widget_theme_hook_set(obj, _theme_hook);
589    elm_widget_can_focus_set(obj, EINA_FALSE);
590    elm_widget_text_set_hook_set(obj, _elm_label_label_set);
591    elm_widget_text_get_hook_set(obj, _elm_label_label_get);
592
593    wd->bgcolor = EINA_FALSE;
594    wd->bg = evas_object_rectangle_add(e);
595    evas_object_color_set(wd->bg, 0, 0, 0, 0);
596
597    wd->linewrap = EINA_FALSE;
598    wd->ellipsis = EINA_FALSE;
599    wd->slidingmode = EINA_FALSE;
600    wd->slidingellipsis = EINA_FALSE;
601    wd->wrap_w = -1;
602    wd->wrap_h = -1;
603    wd->slide_duration = 10;
604
605    wd->lbl = edje_object_add(e);
606    _elm_theme_object_set(obj, wd->lbl, "label", "base", "default");
607    wd->format = eina_stringshare_add("");
608    wd->label = eina_stringshare_add("<br>");
609    edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
610    edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
611
612    elm_widget_resize_object_set(obj, wd->lbl);
613
614    evas_object_event_callback_add(wd->lbl, EVAS_CALLBACK_RESIZE, _lbl_resize, obj);
615
616    _mirrored_set(obj, elm_widget_mirrored_get(obj));
617    wd->changed = 1;
618    _sizing_eval(obj);
619    return obj;
620 }
621
622 /**
623  * Set the label on the label object
624  *
625  * @param obj The label object
626  * @param label The label will be used on the label object
627  *
628  * @ingroup Label
629  */
630 EAPI void
631 elm_label_label_set(Evas_Object *obj, const char *label)
632 {
633   _elm_label_label_set(obj, NULL, label);
634 }
635
636 /**
637  * Get the label used on the label object
638  *
639  * @param obj The label object
640  * @return The string inside the label
641  * @ingroup Label
642  * @deprecated
643  */
644 EAPI const char *
645 elm_label_label_get(const Evas_Object *obj)
646 {
647   return _elm_label_label_get(obj, NULL);
648 }
649
650 /**
651  * Set the wrapping behavior of the label
652  *
653  * @param obj The label object
654  * @param wrap To wrap text or not
655  * @ingroup Label
656  * @deprecated
657  */
658 EAPI void
659 elm_label_line_wrap_set(Evas_Object *obj, Elm_Wrap_Type wrap)
660 {
661    ELM_CHECK_WIDTYPE(obj, widtype);
662    Widget_Data *wd = elm_widget_data_get(obj);
663    const char *wrap_str;
664    int len;
665
666    if (!wd) return;
667    if (wd->linewrap == wrap) return;
668    wd->linewrap = wrap;
669    len = strlen(wd->label);
670    if (len <= 0) return;
671
672    switch (wrap)
673      {
674       case ELM_WRAP_CHAR:
675          wrap_str = "char";
676          break;
677       case ELM_WRAP_WORD:
678          wrap_str = "word";
679          break;
680       case ELM_WRAP_MIXED:
681          wrap_str = "mixed";
682          break;
683       default:
684          wrap_str = "none";
685          break;
686      }
687
688    if (_stringshare_key_value_replace(&wd->format,
689             "wrap", wrap_str, 0) == 0)
690      {
691         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
692         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
693         wd->changed = 1;
694         _sizing_eval(obj);
695      }
696 }
697
698 /**
699  * Get the wrapping behavior of the label
700  *
701  * @param obj The label object
702  * @return Wrap type
703  * @ingroup Label
704  */
705 EAPI Elm_Wrap_Type
706 elm_label_line_wrap_get(const Evas_Object *obj)
707 {
708    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
709    Widget_Data *wd = elm_widget_data_get(obj);
710    if (!wd) return EINA_FALSE;
711    return wd->linewrap;
712 }
713
714 /**
715  * Set wrap width of the label
716  *
717  * @param obj The label object
718  * @param w The wrap width in pixels at a minimum where words need to wrap
719  * @ingroup Label
720  */
721 EAPI void
722 elm_label_wrap_width_set(Evas_Object *obj, Evas_Coord w)
723 {
724    ELM_CHECK_WIDTYPE(obj, widtype);
725    Widget_Data *wd = elm_widget_data_get(obj);
726    if (!wd) return;
727    if (w < 0) w = 0;
728    if (wd->wrap_w == w) 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_w = w;
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 width in pixels at a minimum where words need to wrap
743  * @ingroup Label
744  */
745 EAPI Evas_Coord
746 elm_label_wrap_width_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_w;
752 }
753
754 /**
755  * Set wrap height of the label
756  *
757  * @param obj The label object
758  * @param w The wrap width in pixels at a minimum where words need to wrap
759  * @ingroup Label
760  */
761 EAPI void
762 elm_label_wrap_height_set(Evas_Object *obj,
763                           Evas_Coord   h)
764 {
765    ELM_CHECK_WIDTYPE(obj, widtype);
766    Widget_Data *wd = elm_widget_data_get(obj);
767    if (!wd) return;
768    if (h < 0) h = 0;
769    if (wd->wrap_h == h) return;
770    if (wd->ellipsis)
771      {
772         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
773         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
774      }
775    wd->wrap_h = h;
776    _sizing_eval(obj);
777 }
778
779 /**
780  * get wrap width of the label
781  *
782  * @param obj The label object
783  * @return The wrap height in pixels at a minimum where words need to wrap
784  * @ingroup Label
785  */
786 EAPI Evas_Coord
787 elm_label_wrap_height_get(const Evas_Object *obj)
788 {
789    ELM_CHECK_WIDTYPE(obj, widtype) 0;
790    Widget_Data *wd = elm_widget_data_get(obj);
791    if (!wd) return 0;
792    return wd->wrap_h;
793 }
794
795 /**
796  * Set the font size on the label object.
797  *
798  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
799  * "big", "medium", "small" - or better name them by use:
800  * "title", "footnote", "quote" etc.
801  *
802  * @param obj The label object
803  * @param size font size
804  *
805  * @ingroup Label
806  */
807 EAPI void
808 elm_label_fontsize_set(Evas_Object *obj, int fontsize)
809 {
810    ELM_CHECK_WIDTYPE(obj, widtype);
811    Widget_Data *wd = elm_widget_data_get(obj);
812    Eina_Strbuf *fontbuf = NULL;
813    int len, removeflag = 0;
814
815    if (!wd) return;
816    _elm_dangerous_call_check(__FUNCTION__);
817    len = strlen(wd->label);
818    if (len <= 0) return;
819    fontbuf = eina_strbuf_new();
820    eina_strbuf_append_printf(fontbuf, "%d", fontsize);
821
822    if (fontsize == 0) removeflag = 1;  // remove fontsize tag
823
824    if (_stringshare_key_value_replace(&wd->format, "font_size", eina_strbuf_string_get(fontbuf), removeflag) == 0)
825      {
826         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
827         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
828         wd->changed = 1;
829         _sizing_eval(obj);
830      }
831    eina_strbuf_free(fontbuf);
832 }
833
834 /**
835  * Set the text align on the label object
836  *
837  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
838  * "big", "medium", "small" - or better name them by use:
839  * "title", "footnote", "quote" etc.
840  *
841  * @param obj The label object
842  * @param align align mode ("left", "center", "right")
843  *
844  * @ingroup Label
845  */
846 EAPI void
847 elm_label_text_align_set(Evas_Object *obj, const char *alignmode)
848 {
849    ELM_CHECK_WIDTYPE(obj, widtype);
850    Widget_Data *wd = elm_widget_data_get(obj);
851    int len;
852
853    if (!wd) return;
854    _elm_dangerous_call_check(__FUNCTION__);
855    len = strlen(wd->label);
856    if (len <= 0) return;
857
858    if (_stringshare_key_value_replace(&wd->format, "align", alignmode, 0) == 0)
859      {
860         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
861         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
862      }
863
864    wd->changed = 1;
865    _sizing_eval(obj);
866 }
867
868 /**
869  * Set the text color on the label object
870  *
871  * @param obj The label object
872  * @param r Red property background color of The label object
873  * @param g Green property background color of The label object
874  * @param b Blue property background color of The label object
875  * @param a Alpha property background color of The label object
876  *
877  * @ingroup Label
878  */
879 EAPI void
880 elm_label_text_color_set(Evas_Object *obj,
881                          unsigned int r,
882                          unsigned int g,
883                          unsigned int b,
884                          unsigned int a)
885 {
886    ELM_CHECK_WIDTYPE(obj, widtype);
887    Widget_Data *wd = elm_widget_data_get(obj);
888    Eina_Strbuf *colorbuf = NULL;
889    int len;
890
891    if (!wd) return;
892    _elm_dangerous_call_check(__FUNCTION__);
893    len = strlen(wd->label);
894    if (len <= 0) return;
895    colorbuf = eina_strbuf_new();
896    eina_strbuf_append_printf(colorbuf, "#%02X%02X%02X%02X", r, g, b, a);
897
898    if (_stringshare_key_value_replace(&wd->format, "color", eina_strbuf_string_get(colorbuf), 0) == 0)
899      {
900         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
901         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
902         wd->changed = 1;
903         _sizing_eval(obj);
904      }
905    eina_strbuf_free(colorbuf);
906 }
907
908 /**
909  * Set background color of the label
910  *
911  * NEVER use this. It is for hyper-special cases only. use styles instead. e.g.
912  * "big", "medium", "small" - or better name them by use:
913  * "title", "footnote", "quote" etc.
914  *
915  * @param obj The label object
916  * @param r Red property background color of The label object
917  * @param g Green property background color of The label object
918  * @param b Blue property background color of The label object
919  * @param a Alpha property background alpha of The label object
920  *
921  * @ingroup Label
922  */
923 EAPI void
924 elm_label_background_color_set(Evas_Object *obj,
925                                unsigned int r,
926                                unsigned int g,
927                                unsigned int b,
928                                unsigned int a)
929 {
930    ELM_CHECK_WIDTYPE(obj, widtype);
931    Widget_Data *wd = elm_widget_data_get(obj);
932    if (!wd) return;
933    evas_object_color_set(wd->bg, r, g, b, a);
934
935    if (!wd) return;
936    _elm_dangerous_call_check(__FUNCTION__);
937    if (wd->bgcolor == EINA_FALSE)
938      {
939         wd->bgcolor = 1;
940         edje_object_part_swallow(wd->lbl, "label.swallow.background", wd->bg);
941      }
942 }
943
944 /**
945  * Set the wrapmode of the label
946  *
947  * @param obj The label object
948  * @param wrapmode 0 is charwrap, 1 is wordwrap
949  * @ingroup Label
950  * @deprecated 
951 */
952 EAPI void
953 elm_label_wrap_mode_set(Evas_Object *obj,
954                         Eina_Bool    wrapmode)
955 {
956    return;
957 }
958
959 /**
960  * Set the ellipsis behavior of the label
961  *
962  * @param obj The label object
963  * @param ellipsis To ellipsis text or not
964  * @ingroup Label
965  */
966 EAPI void
967 elm_label_ellipsis_set(Evas_Object *obj, Eina_Bool ellipsis)
968 {
969    ELM_CHECK_WIDTYPE(obj, widtype);
970    Widget_Data *wd = elm_widget_data_get(obj);
971    Eina_Strbuf *fontbuf = NULL;
972    int len, removeflag = 0;
973
974    if (!wd) return;
975    if (wd->ellipsis == ellipsis) return;
976    wd->ellipsis = ellipsis;
977    len = strlen(wd->label);
978    if (len <= 0) return;
979
980    if (ellipsis == EINA_FALSE) removeflag = 1;  // remove fontsize tag
981
982    fontbuf = eina_strbuf_new();
983    eina_strbuf_append_printf(fontbuf, "%f", 1.0);
984
985    if (_stringshare_key_value_replace(&wd->format,
986             "ellipsis", eina_strbuf_string_get(fontbuf), removeflag) == 0)
987      {
988         edje_object_part_text_set(wd->lbl, "elm.text", wd->format);
989         edje_object_part_text_append(wd->lbl, "elm.text", wd->label);
990         wd->changed = 1;
991         _sizing_eval(obj);
992      }
993    eina_strbuf_free(fontbuf);
994
995 }
996
997 /**
998  * Set the text slide of the label
999  *
1000  * @param obj The label object
1001  * @param slide To start slide or stop
1002  * @ingroup Label
1003  */
1004 EAPI void
1005 elm_label_slide_set(Evas_Object *obj,
1006                     Eina_Bool    slide)
1007 {
1008    ELM_CHECK_WIDTYPE(obj, widtype);
1009    Widget_Data *wd = elm_widget_data_get(obj);
1010    if (!wd) return;
1011
1012    if (wd->slidingmode == slide) return;
1013    wd->slidingmode = slide;
1014    _label_sliding_change(obj);
1015    wd->changed = 1;
1016    _sizing_eval(obj);
1017 }
1018
1019 /**
1020  * get the text slide mode of the label
1021  *
1022  * @param obj The label object
1023  * @return slide slide mode value
1024  * @ingroup Label
1025  */
1026 EAPI Eina_Bool
1027 elm_label_slide_get(Evas_Object *obj)
1028 {
1029    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1030    Widget_Data *wd = elm_widget_data_get(obj);
1031    if (!wd) return EINA_FALSE;
1032    return wd->slidingmode;
1033 }
1034
1035 /**
1036  * set the slide duration(speed) of the label
1037  *
1038  * @param obj The label object
1039  * @return The duration time in moving text from slide begin position to slide end position
1040  * @ingroup Label
1041  */
1042 EAPI void
1043 elm_label_slide_duration_set(Evas_Object *obj, double duration)
1044 {
1045    ELM_CHECK_WIDTYPE(obj, widtype);
1046    Widget_Data *wd = elm_widget_data_get(obj);
1047    Edje_Message_Float_Set *msg = alloca(sizeof(Edje_Message_Float_Set) + (sizeof(double)));
1048
1049    if (!wd) return;
1050    wd->slide_duration = duration;
1051    msg->count = 1;
1052    msg->val[0] = wd->slide_duration;
1053    edje_object_message_send(wd->lbl, EDJE_MESSAGE_FLOAT_SET, 0, msg);
1054 }
1055
1056 /**
1057  * get the slide duration(speed) of the label
1058  *
1059  * @param obj The label object
1060  * @return The duration time in moving text from slide begin position to slide end position
1061  * @ingroup Label
1062  */
1063 EAPI double
1064 elm_label_slide_duration_get(Evas_Object *obj)
1065 {
1066    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
1067    Widget_Data *wd = elm_widget_data_get(obj);
1068    if (!wd) return 0;
1069    return wd->slide_duration;
1070 }
1071