textpath: reduces differences between actual position and modified position
[platform/upstream/elementary.git] / src / lib / efl_ui_textpath.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_LAYOUT_PROTECTED
6
7 #include <Elementary.h>
8 #include "elm_priv.h"
9
10 #include "elm_widget_layout.h"
11 //#include "efl_ui_textpath_internal_part.eo.h"
12 //#include "elm_part_helper.h"
13
14
15 #define MY_CLASS EFL_UI_TEXTPATH_CLASS
16
17 #define MY_CLASS_NAME "Efl.Ui.Textpath"
18 #define MY_CLASS_NAME_LEGACY "elm_textpath"
19
20 #define SLICE_DEFAULT_NO 99
21
22 typedef struct _Efl_Ui_Textpath_Point Efl_Ui_Textpath_Point;
23 typedef struct _Efl_Ui_Textpath_Line Efl_Ui_Textpath_Line;
24 typedef struct _Efl_Ui_Textpath_Segment Efl_Ui_Textpath_Segment;
25 typedef struct _Efl_Ui_Textpath_Data Efl_Ui_Textpath_Data;
26
27 struct _Efl_Ui_Textpath_Point
28 {
29    double x;
30    double y;
31 };
32
33 struct _Efl_Ui_Textpath_Line
34 {
35    Efl_Ui_Textpath_Point start;
36    Efl_Ui_Textpath_Point end;
37 };
38
39 struct _Efl_Ui_Textpath_Segment
40 {
41    EINA_INLIST;
42    int length;
43    Efl_Gfx_Path_Command type;
44    union
45      {
46         Eina_Bezier bezier;
47         Efl_Ui_Textpath_Line line;
48      };
49 };
50
51 /* If you need to draw slices using Evas Line,
52  * define the following debug flag manually. */
53 //#define EFL_UI_TEXTPATH_LINE_DEBUG
54
55 struct _Efl_Ui_Textpath_Data
56 {
57    Evas_Object *text_obj;
58    char *text;
59    Efl_Gfx_Shape *path;
60    struct {
61         double x, y;
62         double radius;
63         double start_angle;
64    } circle;
65    Efl_Ui_Textpath_Direction direction;
66    int slice_no;
67    Eina_Bool autofit;
68    Eina_Bool ellipsis;
69
70    Eina_Inlist *segments;
71    int total_length;
72 #ifdef EFL_UI_TEXTPATH_LINE_DEBUG
73    Eina_List *lines;
74 #endif
75 };
76
77 #define EFL_UI_TEXTPATH_DATA_GET(o, sd) \
78    Efl_Ui_Textpath_Data *sd = eo_data_scope_get(o, EFL_UI_TEXTPATH_CLASS)
79
80 static inline double
81 _deg_to_rad(double angle)
82 {
83    return angle / 180 * M_PI;
84 }
85
86 static void
87 _segment_draw(Efl_Ui_Textpath_Data *pd, int slice_no, double dt, double dist,
88               int w1, int cmp, Evas_Map *map, Eina_Bezier bezier,
89               int *last_x1, int *last_y1, int *last_x2, int *last_y2)
90 {
91    int x = 0, y = 0, w = 0, h = 0;
92    int i;
93    double u0, u1, v0, v1;
94    double t;
95    double px, py, px2, py2;
96    double rad;
97    Eina_Vector2 vec, nvec, vec0, vec1, vec2, vec3;
98    Eina_Matrix2 mat;
99 #ifdef EFL_UI_TEXTPATH_LINE_DEBUG
100    static Eina_Bool yello_color_flag = EINA_FALSE;
101    yello_color_flag = !yello_color_flag;
102 #endif
103
104    evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
105
106    rad = _deg_to_rad(90);
107    eina_matrix2_values_set(&mat, cos(rad), -sin(rad), sin(rad), cos(rad));
108
109    eina_bezier_values_get(&bezier, NULL, NULL, NULL, NULL, NULL, NULL, &px2, &py2);
110    t = 0;
111    eina_bezier_point_at(&bezier, t, &px, &py);
112    eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
113
114    vec.x = (px2 - px);
115    vec.y = (py2 - py);
116    eina_vector2_normalize(&nvec, &vec);
117
118    eina_vector2_transform(&vec, &mat, &nvec);
119    eina_vector2_normalize(&nvec, &vec);
120    eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
121
122    vec1.x = (vec.x + px);
123    vec1.y = (vec.y + py);
124    vec2.x = (-vec.x + px);
125    vec2.y = (-vec.y + py);
126
127    if (cmp == 0)
128      {
129         *last_x1 = (int) floor(vec1.x + x + 0.5);
130         *last_y1 = (int) floor(vec1.y + y + 0.5);
131         *last_x2 = (int) floor(vec2.x + x + 0.5);
132         *last_y2 = (int) floor(vec2.y + y + 0.5);
133      }
134
135    //add points to map
136    for (i = 0; i < slice_no; i++)
137      {
138         int mp0_x, mp0_y;
139         int mp1_x, mp1_y;
140         int mp2_x, mp2_y;
141         int mp3_x, mp3_y;
142         double next_dt = dt;
143
144         //v0, v3
145         vec0.x = vec1.x;
146         vec0.y = vec1.y;
147         vec3.x = vec2.x;
148         vec3.y = vec2.y;
149
150         //UV
151         u0 = w1 + i * dist;
152         u1 = u0 + dist;
153         if (u1 > w)
154           u1 = w;
155         v0 = (double) 0;
156         v1 = (double) h;
157
158         /* If u1 is modified not to exceed its end,
159          * modify next_dt according to changes of dist. */
160         if (u1 < u0 + dist)
161           next_dt = dt * (u1 - u0) / dist;
162
163         //v1, v2
164         t = (double) (i * dt) + next_dt;
165         eina_bezier_point_at(&bezier, t, &px, &py);
166         eina_bezier_point_at(&bezier, t + next_dt, &px2, &py2);
167
168         vec.x = (px2 - px);
169         vec.y = (py2 - py);
170         eina_vector2_normalize(&nvec, &vec);
171         eina_vector2_transform(&vec, &mat, &nvec);
172         eina_vector2_normalize(&nvec, &vec);
173         eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
174
175         vec1.x = (vec.x + px);
176         vec1.y = (vec.y + py);
177         vec2.x = (-vec.x + px);
178         vec2.y = (-vec.y + py);
179
180         /* Set mp1, mp2 position according to difference between previous points and next points.
181          * It improves smoothness of curve's slope changing. It can show smooth result.
182          * But, it can cause huge differeces from actual positions.
183          * */
184         mp0_x = *last_x1;
185         mp0_y = *last_y1;
186         mp1_x = *last_x1 + (int) floor(vec1.x - vec0.x + 0.5);
187         mp1_y = *last_y1 + (int) floor(vec1.y - vec0.y + 0.5);
188         mp2_x = *last_x2 + (int) floor(vec2.x - vec3.x + 0.5);
189         mp2_y = *last_y2 + (int) floor(vec2.y - vec3.y + 0.5);
190         mp3_x = *last_x2;
191         mp3_y = *last_y2;
192
193         /* It reduces differences between actual position and modified position. */
194         mp1_x += (int)floor(((double)vec1.x - mp1_x) / 2 + 0.5);
195         mp1_y += (int)floor(((double)vec1.y - mp1_y) / 2 + 0.5);
196         mp2_x += (int)floor(((double)vec2.x - mp2_x) / 2 + 0.5);
197         mp2_y += (int)floor(((double)vec2.y - mp2_y) / 2 + 0.5);
198
199         evas_map_point_coord_set(map, cmp + i * 4, mp0_x, mp0_y, 0);
200         evas_map_point_coord_set(map, cmp + i * 4 + 1, mp1_x, mp1_y, 0);
201         evas_map_point_coord_set(map, cmp + i * 4 + 2, mp2_x, mp2_y, 0);
202         evas_map_point_coord_set(map, cmp + i * 4 + 3, mp3_x, mp3_y, 0);
203
204         evas_map_point_image_uv_set(map, cmp + i * 4, u0, v0);
205         evas_map_point_image_uv_set(map, cmp + i * 4 + 1, u1, v0);
206         evas_map_point_image_uv_set(map, cmp + i * 4 + 2, u1, v1);
207         evas_map_point_image_uv_set(map, cmp + i * 4 + 3, u0, v1);
208
209         *last_x1 = mp1_x;
210         *last_y1 = mp1_y;
211         *last_x2 = mp2_x;
212         *last_y2 = mp2_y;
213
214 #ifdef EFL_UI_TEXTPATH_LINE_DEBUG
215         Evas_Object *line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
216         pd->lines = eina_list_append(pd->lines, line);
217         if (yello_color_flag)
218           evas_object_color_set(line, 255, 255, 0, 255);
219         else
220           evas_object_color_set(line, 255, 0, 0, 255);
221         evas_object_line_xy_set(line,
222                                 mp0_x, mp0_y,
223                                 mp1_x, mp1_y);
224         evas_object_show(line);
225
226         line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
227         pd->lines = eina_list_append(pd->lines, line);
228         if (yello_color_flag)
229           evas_object_color_set(line, 255, 255, 0, 255);
230         else
231           evas_object_color_set(line, 255, 0, 0, 255);
232         evas_object_line_xy_set(line,
233                                 mp1_x, mp1_y,
234                                 mp2_x, mp2_y);
235         evas_object_show(line);
236
237         line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
238         pd->lines = eina_list_append(pd->lines, line);
239         if (yello_color_flag)
240           evas_object_color_set(line, 255, 255, 0, 255);
241         else
242           evas_object_color_set(line, 255, 0, 0, 255);
243         evas_object_line_xy_set(line,
244                                 mp2_x, mp2_y,
245                                 mp3_x, mp3_y);
246         evas_object_show(line);
247
248         line = evas_object_line_add(evas_object_evas_get(pd->text_obj));
249         pd->lines = eina_list_append(pd->lines, line);
250         if (yello_color_flag)
251           evas_object_color_set(line, 255, 255, 0, 255);
252         else
253           evas_object_color_set(line, 255, 0, 0, 255);
254         evas_object_line_xy_set(line,
255                                 mp3_x, mp3_y,
256                                 mp0_x, mp0_y);
257         evas_object_show(line);
258 #endif
259
260         if (u1 >= w) break;
261      }
262 }
263
264 static void
265 _text_on_line_draw(Efl_Ui_Textpath_Data *pd, int w1, int w2, int cmp, Evas_Map *map, Efl_Ui_Textpath_Line line)
266 {
267    double x1, x2, y1, y2;
268    Evas_Coord x, y, w, h;
269    double line_len, len, sina, cosa;
270
271    x1 = line.start.x;
272    y1 = line.start.y;
273    x2 = line.end.x;
274    y2 = line.end.y;
275
276    line_len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
277    len = w2 - w1;
278    if (line_len > len)
279      {
280         x2 = x1 + len * (x2 - x1) / line_len;
281         y2 = y1 + len * (y2 - y1) / line_len;
282      }
283
284    evas_object_geometry_get(pd->text_obj, &x, &y, &w, &h);
285
286    len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
287    sina = (y2 - y1) / len;
288    cosa = (x2 - x1) / len;
289
290    h = h / 2;
291    evas_map_point_coord_set(map, cmp + 3, x1 - h * sina, y1 + h * cosa, 0);
292    evas_map_point_coord_set(map, cmp + 2, x2 - h * sina, y2 + h * cosa, 0);
293    evas_map_point_coord_set(map, cmp + 1, x2 + h * sina, y2 - h * cosa, 0);
294    evas_map_point_coord_set(map, cmp + 0, x1 + h * sina, y1 - h * cosa, 0);
295
296    h *= 2;
297    evas_map_point_image_uv_set(map, cmp + 0, w1, 0);
298    evas_map_point_image_uv_set(map, cmp + 1, w2, 0);
299    evas_map_point_image_uv_set(map, cmp + 2, w2, h);
300    evas_map_point_image_uv_set(map, cmp + 3, w1, h);
301 }
302
303 static int
304 _map_point_calc(Efl_Ui_Textpath_Data *pd)
305 {
306    int map_no = 0;
307    Efl_Ui_Textpath_Segment *seg;
308
309    EINA_INLIST_FOREACH(pd->segments, seg)
310      {
311         if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
312           {
313              map_no++;
314           }
315         else if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
316           {
317              int no = (int)ceil(pd->slice_no * seg->length / (double)pd->total_length);
318              if (no == 0) no = 1;
319              map_no += no;
320           }
321      }
322    map_no *= 4;
323
324    return map_no;
325 }
326
327 static void
328 _text_draw(Efl_Ui_Textpath_Data *pd)
329 {
330    Efl_Ui_Textpath_Segment *seg;
331    Evas_Map *map;
332    int w, h, w1, w2;
333    int remained_w;
334    int cur_map_point = 0, map_point_no;
335    int last_x1, last_y1, last_x2, last_y2;
336
337    last_x1 = last_y1 = last_x2 = last_y2 = 0;
338
339    evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
340    if (pd->autofit)
341      remained_w = w;
342    else
343      remained_w = pd->total_length;
344
345    map_point_no = _map_point_calc(pd);
346    if (map_point_no == 0)
347      {
348         evas_object_map_enable_set(pd->text_obj, EINA_FALSE);
349         return;
350      }
351    map = evas_map_new(map_point_no);
352    /* TIZEN_ONLY(20180302): update map when object's position is updated */
353    evas_map_util_object_move_sync_set(map, EINA_TRUE);
354    /* END */
355
356 #ifdef EFL_UI_TEXTPATH_LINE_DEBUG
357    Evas_Object *line;
358    EINA_LIST_FREE(pd->lines, line)
359       evas_object_del(line);
360 #endif
361
362    w1 = w2 = 0;
363    EINA_INLIST_FOREACH(pd->segments, seg)
364      {
365         int len = seg->length;
366         if (!pd->autofit)
367           len = (double)seg->length * w / (double)pd->total_length;
368         if (remained_w <= 0)
369           break;
370         w2 = w1 + len;
371         if (w2 > w)
372           w2 = w;
373         if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
374           {
375              _text_on_line_draw(pd, w1, w2, cur_map_point, map, seg->line);
376              cur_map_point += 4;
377           }
378         else
379           {
380              double slice_value, dt, dist;
381              int slice_no;
382
383              slice_value = pd->slice_no * seg->length / (double)pd->total_length;
384              dt = (double)pd->total_length / (pd->slice_no * seg->length);
385
386              if (pd->autofit)
387                dist = (double)pd->total_length / (double)pd->slice_no;
388              else
389                dist = (double)pd->total_length * (w2 - w1) / ((double)pd->slice_no * seg->length);
390
391              slice_no = (int)ceil(slice_value);
392              dt = (double)slice_value * dt / (double)slice_no;
393              dist = (double)slice_value * dist / (double)slice_no;
394
395              _segment_draw(pd, slice_no, dt, dist,
396                            w1, cur_map_point, map, seg->bezier,
397                            &last_x1, &last_y1, &last_x2, &last_y2);
398              cur_map_point += slice_no * 4;
399           }
400         w1 = w2;
401         remained_w -= seg->length;
402      }
403    evas_object_map_enable_set(pd->text_obj, EINA_TRUE);
404    evas_object_map_set(pd->text_obj, map);
405    evas_map_free(map);
406 }
407
408 static void
409 _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd, Eina_Bool set_min)
410 {
411    const Efl_Gfx_Path_Command *cmd;
412    const double *points;
413    Efl_Ui_Textpath_Segment *seg;
414
415    EINA_INLIST_FREE(pd->segments, seg)
416      {
417         pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
418         free(seg);
419      }
420
421    Evas_Coord x, y;
422    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
423
424    pd->total_length = 0;
425    eo_do(obj, efl_gfx_shape_path_get(&cmd, &points));
426    if (cmd)
427      {
428         int pos = -1;
429         Eina_Rectangle *rect = eina_rectangle_new(0, 0, 0, 0);
430         double px0 = 0.0, py0 = 0.0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1;
431
432         while (*cmd != EFL_GFX_PATH_COMMAND_TYPE_END)
433           {
434
435              if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
436                {
437                   pos++;
438                   px0 = points[pos] + x;
439                   pos++;
440                   py0 = points[pos] + y;
441                }
442              else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
443                {
444                   Eina_Bezier bz;
445                   double bx, by, bw, bh;
446                   Eina_Rectangle *brect;
447
448                   pos++;
449                   ctrl_x0 = points[pos] + x;
450                   pos++;
451                   ctrl_y0 = points[pos] + y;
452                   pos++;
453                   ctrl_x1 = points[pos] + x;
454                   pos++;
455                   ctrl_y1 = points[pos] + y;
456                   pos++;
457                   px1 = points[pos] + x;
458                   pos++;
459                   py1 = points[pos] + y;
460
461                   eina_bezier_values_set(&bz, px0, py0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1);
462                   seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
463                   if (!seg)
464                     {
465                        ERR("Failed to allocate segment");
466                        px0 = px1;
467                        py0 = py1;
468                        continue;
469                     }
470                   seg->length = eina_bezier_length_get(&bz);
471                   seg->bezier = bz;
472                   seg->type = EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO;
473                   pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
474                   pd->total_length += seg->length;
475
476                   //move points
477                   px0 = px1;
478                   py0 = py1;
479
480                   eina_bezier_bounds_get(&bz, &bx, &by, &bw, &bh);
481                   brect = eina_rectangle_new(bx, by, bw, bh);
482                   eina_rectangle_union(rect, brect);
483                   eina_rectangle_free(brect);
484                }
485              else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
486                {
487                   Eina_Rectangle *lrect;
488
489                   pos++;
490                   px1 = points[pos] + x;
491                   pos++;
492                   py1 = points[pos] + y;
493
494                   seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
495                   if (!seg)
496                     {
497                        ERR("Failed to allocate segment");
498                        px0 = px1;
499                        py0 = py1;
500                     }
501                   seg->type = EFL_GFX_PATH_COMMAND_TYPE_LINE_TO;
502                   seg->line.start.x = px0;
503                   seg->line.start.y = py0;
504                   seg->line.end.x = px1;
505                   seg->line.end.y = py1;
506                   seg->length = sqrt((px1 - px0)*(px1 - px0) + (py1 - py0)*(py1 - py0));
507                   pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
508                   pd->total_length += seg->length;
509
510                   lrect = eina_rectangle_new(px0, py0, px1 - px0, py1 - py0);
511                   eina_rectangle_union(rect, lrect);
512                   eina_rectangle_free(lrect);
513                }
514              cmd++;
515           }
516         if (set_min)
517           {
518              evas_object_size_hint_min_set(obj, rect->w, rect->h);
519           }
520         eina_rectangle_free(rect);
521      }
522 }
523
524 static void
525 _sizing_eval(Efl_Ui_Textpath_Data *pd)
526 {
527    _text_draw(pd);
528 }
529
530 static void
531 _textpath_ellipsis_set(Efl_Ui_Textpath_Data *pd, Eina_Bool enabled)
532 {
533    const char *format;
534
535    edje_object_part_text_style_user_pop(pd->text_obj, "elm.text");
536    if (enabled)
537      {
538         Eina_Strbuf *buf = eina_strbuf_new();
539
540         eina_strbuf_append_printf(buf, "DEFAULT='ellipsis=1.0'");
541         format = eina_stringshare_add(eina_strbuf_string_get(buf));
542         eina_strbuf_free(buf);
543         edje_object_part_text_style_user_push(pd->text_obj, "elm.text", format);
544      }
545 }
546
547 static void
548 _ellipsis_set(Efl_Ui_Textpath_Data *pd)
549 {
550    if (!pd->text_obj) return;
551
552    Evas_Coord w = 0, h = 0;
553    Eina_Bool is_ellipsis = EINA_FALSE;
554    const Evas_Object *tb;
555
556    tb = edje_object_part_object_get(pd->text_obj, "elm.text");
557    evas_object_textblock_size_native_get(tb, &w, &h);
558    evas_object_size_hint_min_set(pd->text_obj, w, h);
559    if (pd->ellipsis)
560      {
561         if (w > pd->total_length)
562           {
563              is_ellipsis = EINA_TRUE;
564              w = pd->total_length;
565           }
566      }
567    evas_object_resize(pd->text_obj, w, h);
568    _textpath_ellipsis_set(pd, is_ellipsis);
569 }
570
571 static Eina_Bool
572 //_path_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
573 _path_changed_cb(void *data,
574                     Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
575                     void *event_info EINA_UNUSED)
576 {
577    EFL_UI_TEXTPATH_DATA_GET(data, sd);
578
579    _path_data_get(data, sd, EINA_TRUE);
580    _sizing_eval(sd);
581
582    return EINA_TRUE;
583 }
584
585 static Eina_Bool
586 _textpath_text_set_internal(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part EINA_UNUSED, const char *text)
587 {
588    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
589    Eina_Bool ret = EINA_TRUE;
590
591    if (!text) text = "";
592    //ret = edje_object_part_text_set(pd->text_obj, part, text);
593    ret = edje_object_part_text_set(pd->text_obj, "elm.text", text);
594    _ellipsis_set(pd);
595
596    return ret;
597 }
598
599 /*EOLIAN static void
600 _efl_ui_textpath_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
601 {
602    _sizing_eval(pd);
603 }*/
604
605
606 EOLIAN static void
607 _efl_ui_textpath_elm_layout_sizing_eval(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
608 {
609    _sizing_eval(pd);
610 }
611
612 EOLIAN static void
613 _efl_ui_textpath_evas_object_smart_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
614 {
615     _sizing_eval(pd);
616 }
617
618 EOLIAN static void
619 //_efl_ui_textpath_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Textpath_Data *priv)
620 _efl_ui_textpath_evas_object_smart_add(Eo *obj, Efl_Ui_Textpath_Data *priv)
621 {
622    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
623
624    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
625    elm_widget_sub_object_parent_add(obj);
626
627    priv->text_obj = edje_object_add(evas_object_evas_get(obj));
628    elm_widget_theme_object_set(obj, priv->text_obj, "textpath", "base",
629                                elm_widget_style_get(obj));
630    evas_object_size_hint_weight_set(priv->text_obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
631    evas_object_size_hint_align_set(priv->text_obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
632    evas_object_show(priv->text_obj);
633
634    evas_object_smart_member_add(priv->text_obj, obj);
635    elm_widget_sub_object_add(obj, priv->text_obj);
636
637    //efl_event_callback_add(obj, EFL_GFX_PATH_EVENT_CHANGED, _path_changed_cb, obj);
638    eo_do(obj, eo_event_callback_add
639          (EFL_GFX_PATH_CHANGED, _path_changed_cb, obj));
640 }
641
642 EOLIAN static void
643 _efl_ui_textpath_class_constructor(Eo_Class *klass)
644 {
645    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
646 }
647
648 //EOLIAN static Efl_Object *
649 //_efl_ui_textpath_efl_object_constructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
650 EOLIAN static Eo*
651 _efl_ui_textpath_eo_base_constructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
652 {
653    //obj = efl_constructor(efl_super(obj, MY_CLASS));
654    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
655    pd->autofit = EINA_TRUE;
656    pd->slice_no = SLICE_DEFAULT_NO;
657    pd->direction = EFL_UI_TEXTPATH_DIRECTION_CW;
658
659    return obj;
660 }
661
662 EOLIAN static void
663 //_efl_ui_textpath_efl_object_destructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
664 _efl_ui_textpath_eo_base_destructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
665 {
666    Efl_Ui_Textpath_Segment *seg;
667
668    if (pd->text) free(pd->text);
669    if (pd->text_obj) evas_object_del(pd->text_obj);
670    EINA_INLIST_FREE(pd->segments, seg)
671      {
672         pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
673         free(seg);
674      }
675
676 #ifdef EFL_UI_TEXTPATH_LINE_DEBUG
677    Evas_Object *line;
678    EINA_LIST_FREE(pd->lines, line)
679       evas_object_del(line);
680 #endif
681
682    //efl_destructor(efl_super(obj, MY_CLASS));
683    eo_do_super(obj, MY_CLASS, eo_destructor());
684 }
685
686 EOLIAN static Eina_Bool
687 _efl_ui_textpath_elm_layout_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
688 {
689    return _textpath_text_set_internal(obj, pd, part, text);
690 }
691
692 EOLIAN static const char *
693 _efl_ui_textpath_elm_layout_text_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, const char *part)
694 {
695    return edje_object_part_text_get(pd->text_obj, part);
696 }
697
698 /*
699 EOLIAN static Eina_Bool
700 _efl_ui_textpath_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
701 {
702    return _textpath_text_set_internal(obj, pd, part, text);
703 }
704
705 EOLIAN static const char *
706 _efl_ui_textpath_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, const char *part)
707 {
708    return edje_object_part_text_get(pd->text_obj, part);
709 }
710
711 EOLIAN static void
712 _efl_ui_textpath_efl_text_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *text)
713 {
714    _textpath_text_set_internal(obj, pd, "elm.text", text);
715 }
716
717 EOLIAN static const char *
718 _efl_ui_textpath_efl_text_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
719 {
720    return edje_object_part_text_get(pd->text_obj, "elm.text");
721 }*/
722
723 //EOLIAN static Efl_Ui_Theme_Apply
724 EOLIAN static Elm_Theme_Apply
725 _efl_ui_textpath_elm_widget_theme_apply(Eo *obj, Efl_Ui_Textpath_Data *pd)
726 {
727    Elm_Theme_Apply ret = ELM_THEME_APPLY_FAILED;
728
729    eo_do_super(obj, MY_CLASS, ret = elm_obj_widget_theme_apply());
730    if (!ret) return ELM_THEME_APPLY_FAILED;
731
732    elm_widget_theme_object_set(obj, pd->text_obj, "textpath", "base",
733                                elm_widget_style_get(obj));
734    _ellipsis_set(pd);
735
736    return ret;
737 }
738
739
740 EOLIAN static void
741 //_efl_ui_textpath_evas_object_position_set(Eo *obj, Efl_Ui_Textpath_Data *pd, Evas_Coord x, Evas_Coord y)
742 _efl_ui_textpath_evas_object_smart_move(Eo *obj, Efl_Ui_Textpath_Data *pd, Evas_Coord x, Evas_Coord y)
743 {
744    eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
745
746    /* TIZEN_ONLY(20180302): update map when object's position is updated
747     * Do Nothing. The position is not updated to the object in this function.
748     * Test with evas_object_geometry_get().
749    _path_data_get(obj, pd, EINA_FALSE);
750    _text_draw(pd);
751     */
752    /* END */
753 }
754
755 /*
756 EOLIAN static void
757 _efl_ui_textpath_evas_object_resize(Eo *obj, Efl_Ui_Textpath_Data *pd EINA_UNUSED, Evas_Coord w, Evas_Coord h)
758 {
759    eo_do_super(obj, MY_CLASS, evas_object_resize(w, h));
760 }*/
761
762 EOLIAN static void
763 _efl_ui_textpath_circle_set(Eo *obj, Efl_Ui_Textpath_Data *pd, double x, double y, double radius, double start_angle, Efl_Ui_Textpath_Direction direction)
764 {
765    if (pd->circle.x == x && pd->circle.y == y &&
766        pd->circle.radius == radius &&
767        pd->circle.start_angle == start_angle &&
768        pd->direction == direction &&
769        _map_point_calc(pd) > 0)
770      {
771         ERR("Same circle");
772         return;
773      }
774    pd->circle.x = x;
775    pd->circle.y = y;
776    pd->circle.radius = radius;
777    pd->circle.start_angle = start_angle;
778    pd->direction = direction;
779
780    eo_do(obj, efl_gfx_shape_reset());
781    if (direction == EFL_UI_TEXTPATH_DIRECTION_CW)
782      {
783         eo_do(obj, efl_gfx_shape_append_arc(x - radius, y - radius, radius * 2,
784                                 radius * 2,  start_angle, -360));
785      }
786    else
787      {
788         eo_do(obj, efl_gfx_shape_append_arc(x - radius, y - radius, radius * 2,
789                                 radius * 2,  start_angle, 360));
790      }
791
792    _sizing_eval(pd);
793 }
794
795 EOLIAN static Eina_Bool
796 _efl_ui_textpath_autofit_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
797 {
798    return pd->autofit;
799 }
800
801 EOLIAN static void
802 _efl_ui_textpath_autofit_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool autofit)
803 {
804    if (pd->autofit == autofit) return;
805    pd->autofit = autofit;
806    _sizing_eval(pd);
807 }
808
809 EOLIAN static int
810 _efl_ui_textpath_slice_number_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
811 {
812    return pd->slice_no;
813 }
814
815 EOLIAN static void
816 _efl_ui_textpath_slice_number_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, int slice_no)
817 {
818    if (pd->slice_no == slice_no) return;
819    pd->slice_no = slice_no;
820    _sizing_eval(pd);
821 }
822
823 EOLIAN static void
824 _efl_ui_textpath_ellipsis_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool ellipsis)
825 {
826    if (pd->ellipsis == ellipsis) return;
827    pd->ellipsis = ellipsis;
828
829    _ellipsis_set(pd);
830    _sizing_eval(pd);
831 }
832
833 EOLIAN static Eina_Bool
834 _efl_ui_textpath_ellipsis_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
835 {
836    return pd->ellipsis;
837 }
838
839 /* Efl.Part begin */
840 //ELM_PART_OVERRIDE(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
841 //ELM_PART_OVERRIDE_TEXT_SET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
842 //ELM_PART_OVERRIDE_TEXT_GET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
843 //#include "efl_ui_textpath_internal_part.eo.c"
844 /* Efl.Part end */
845
846 EAPI Evas_Object *
847 elm_textpath_add(Evas_Object *parent)
848 {
849    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
850    Evas_Object *obj = eo_add(MY_CLASS, parent);
851
852    return obj;
853 }
854
855 #define EFL_UI_TEXTPATH_EXTRA_OPS \
856       EFL_CANVAS_GROUP_ADD_OPS(efl_ui_textpath)
857
858 #include "efl_ui_textpath.eo.c"