2 # include "elementary_config.h"
5 #define ELM_LAYOUT_PROTECTED
7 #include <Elementary.h>
10 #include "elm_widget_layout.h"
11 //#include "efl_ui_textpath_internal_part.eo.h"
12 //#include "elm_part_helper.h"
15 #define MY_CLASS EFL_UI_TEXTPATH_CLASS
17 #define MY_CLASS_NAME "Efl.Ui.Textpath"
18 #define MY_CLASS_NAME_LEGACY "elm_textpath"
20 #define SLICE_DEFAULT_NO 99
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;
27 struct _Efl_Ui_Textpath_Point
33 struct _Efl_Ui_Textpath_Line
35 Efl_Ui_Textpath_Point start;
36 Efl_Ui_Textpath_Point end;
39 struct _Efl_Ui_Textpath_Segment
43 Efl_Gfx_Path_Command type;
47 Efl_Ui_Textpath_Line line;
51 struct _Efl_Ui_Textpath_Data
53 Evas_Object *text_obj;
61 Efl_Ui_Textpath_Direction direction;
66 Eina_Inlist *segments;
70 #define EFL_UI_TEXTPATH_DATA_GET(o, sd) \
71 Efl_Ui_Textpath_Data *sd = eo_data_scope_get(o, EFL_UI_TEXTPATH_CLASS)
74 _deg_to_rad(double angle)
76 return angle / 180 * M_PI;
80 _segment_draw(Efl_Ui_Textpath_Data *pd, int slice_no, int w1, int w2, int cmp, Evas_Map *map, Eina_Bezier bezier)
82 int x = 0, y = 0, w = 0, h = 0;
84 double u0, u1, v0, v1;
86 double px, py, px2, py2;
88 Eina_Vector2 vec, nvec, vec0, vec1, vec2, vec3;
92 evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
93 seg_len = eina_bezier_length_get(&bezier);
95 dt = len / (seg_len * (double) slice_no);
97 dt = 1.0 / (double) slice_no;
98 dist = len / (double)slice_no;
99 rad = _deg_to_rad(90);
100 eina_matrix2_values_set(&mat, cos(rad), -sin(rad), sin(rad), cos(rad));
102 eina_bezier_values_get(&bezier, NULL, NULL, NULL, NULL, NULL, NULL, &px2, &py2);
104 eina_bezier_point_at(&bezier, t, &px, &py);
105 eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
109 eina_vector2_normalize(&nvec, &vec);
111 eina_vector2_transform(&vec, &mat, &nvec);
112 eina_vector2_normalize(&nvec, &vec);
113 eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
115 vec1.x = (vec.x + px);
116 vec1.y = (vec.y + py);
117 vec2.x = (-vec.x + px);
118 vec2.y = (-vec.y + py);
121 for (i = 0; i < slice_no; i++)
130 t = ((double) (i + 1) * dt);
131 eina_bezier_point_at(&bezier, t, &px, &py);
132 eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
136 eina_vector2_normalize(&nvec, &vec);
137 eina_vector2_transform(&vec, &mat, &nvec);
138 eina_vector2_normalize(&nvec, &vec);
139 eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
141 vec1.x = (vec.x + px);
142 vec1.y = (vec.y + py);
143 vec2.x = (-vec.x + px);
144 vec2.y = (-vec.y + py);
146 evas_map_point_coord_set(map, cmp + i * 4, (int) vec0.x + x, (int) vec0.y + y, 0);
147 evas_map_point_coord_set(map, cmp + i * 4 + 1, (int) vec1.x + x, (int) vec1.y + y, 0);
148 evas_map_point_coord_set(map, cmp + i * 4 + 2, (int) vec2.x + x, (int) vec2.y + y, 0);
149 evas_map_point_coord_set(map, cmp + i * 4 + 3, (int) vec3.x + x, (int) vec3.y + y, 0);
157 evas_map_point_image_uv_set(map, cmp + i * 4, u0, v0);
158 evas_map_point_image_uv_set(map, cmp + i * 4 + 1, u1, v0);
159 evas_map_point_image_uv_set(map, cmp + i * 4 + 2, u1, v1);
160 evas_map_point_image_uv_set(map, cmp + i * 4 + 3, u0, v1);
165 _text_on_line_draw(Efl_Ui_Textpath_Data *pd, int w1, int w2, int cmp, Evas_Map *map, Efl_Ui_Textpath_Line line)
167 double x1, x2, y1, y2;
168 Evas_Coord x, y, w, h;
169 double line_len, len, sina, cosa;
176 line_len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
180 x2 = x1 + len * (x2 - x1) / line_len;
181 y2 = y1 + len * (y2 - y1) / line_len;
184 evas_object_geometry_get(pd->text_obj, &x, &y, &w, &h);
186 len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
187 sina = (y2 - y1) / len;
188 cosa = (x2 - x1) / len;
191 evas_map_point_coord_set(map, cmp + 3, x1 - h * sina, y1 + h * cosa, 0);
192 evas_map_point_coord_set(map, cmp + 2, x2 - h * sina, y2 + h * cosa, 0);
193 evas_map_point_coord_set(map, cmp + 1, x2 + h * sina, y2 - h * cosa, 0);
194 evas_map_point_coord_set(map, cmp + 0, x1 + h * sina, y1 - h * cosa, 0);
197 evas_map_point_image_uv_set(map, cmp + 0, w1, 0);
198 evas_map_point_image_uv_set(map, cmp + 1, w2, 0);
199 evas_map_point_image_uv_set(map, cmp + 2, w2, h);
200 evas_map_point_image_uv_set(map, cmp + 3, w1, h);
204 _map_point_calc(Efl_Ui_Textpath_Data *pd)
207 Efl_Ui_Textpath_Segment *seg;
209 EINA_INLIST_FOREACH(pd->segments, seg)
211 if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
215 else if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
217 int no = pd->slice_no * seg->length / (double)pd->total_length;
227 _text_draw(Efl_Ui_Textpath_Data *pd)
229 Efl_Ui_Textpath_Segment *seg;
231 double slice_unit, slice_len;
234 int total_slice, drawn_slice = 0;
235 int cur_map_point = 0, map_point_no;
237 evas_object_geometry_get(pd->text_obj, NULL, NULL, &w, &h);
241 remained_w = pd->total_length;
242 slice_unit = (double)pd->slice_no / pd->total_length;
244 slice_len = 1.0 / slice_unit;
245 total_slice = w / slice_len + 1;
247 map_point_no = _map_point_calc(pd);
248 if (map_point_no == 0)
251 evas_object_map_enable_set(pd->text_obj, EINA_FALSE);
254 map = evas_map_new(map_point_no);
257 EINA_INLIST_FOREACH(pd->segments, seg)
259 int len = seg->length;
261 len = (double)seg->length * w / (double)pd->total_length;
267 if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
270 _text_on_line_draw(pd, w1, w2, cur_map_point, map, seg->line);
276 slice_no = pd->slice_no * seg->length / (double)pd->total_length;
278 slice_no = len * slice_unit + 1;
280 slice_no = total_slice - drawn_slice;
281 drawn_slice += slice_no;
282 _segment_draw(pd, slice_no, w1, w2, cur_map_point, map, seg->bezier);
283 cur_map_point += slice_no * 4;
288 evas_object_map_enable_set(pd->text_obj, EINA_TRUE);
289 evas_object_map_set(pd->text_obj, map);
294 _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd, Eina_Bool set_min)
296 const Efl_Gfx_Path_Command *cmd;
297 const double *points;
298 Efl_Ui_Textpath_Segment *seg;
300 EINA_INLIST_FREE(pd->segments, seg)
302 pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
307 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
309 pd->total_length = 0;
310 eo_do(obj, efl_gfx_shape_path_get(&cmd, &points));
314 Eina_Rectangle *rect = eina_rectangle_new(0, 0, 0, 0);
315 double px0 = 0.0, py0 = 0.0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1;
317 while (*cmd != EFL_GFX_PATH_COMMAND_TYPE_END)
320 if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
323 px0 = points[pos] + x;
325 py0 = points[pos] + y;
327 else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
330 double bx, by, bw, bh;
331 Eina_Rectangle *brect;
334 ctrl_x0 = points[pos] + x;
336 ctrl_y0 = points[pos] + y;
338 ctrl_x1 = points[pos] + x;
340 ctrl_y1 = points[pos] + y;
342 px1 = points[pos] + x;
344 py1 = points[pos] + y;
346 eina_bezier_values_set(&bz, px0, py0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1);
347 seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
350 ERR("Failed to allocate segment");
355 seg->length = eina_bezier_length_get(&bz);
357 seg->type = EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO;
358 pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
359 pd->total_length += seg->length;
365 eina_bezier_bounds_get(&bz, &bx, &by, &bw, &bh);
366 brect = eina_rectangle_new(bx, by, bw, bh);
367 eina_rectangle_union(rect, brect);
368 eina_rectangle_free(brect);
370 else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
372 Eina_Rectangle *lrect;
375 px1 = points[pos] + x;
377 py1 = points[pos] + y;
379 seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
382 ERR("Failed to allocate segment");
386 seg->type = EFL_GFX_PATH_COMMAND_TYPE_LINE_TO;
387 seg->line.start.x = px0;
388 seg->line.start.y = py0;
389 seg->line.end.x = px1;
390 seg->line.end.y = py1;
391 seg->length = sqrt((px1 - px0)*(px1 - px0) + (py1 - py0)*(py1 - py0));
392 pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
393 pd->total_length += seg->length;
395 lrect = eina_rectangle_new(px0, py0, px1 - px0, py1 - py0);
396 eina_rectangle_union(rect, lrect);
397 eina_rectangle_free(lrect);
403 evas_object_size_hint_min_set(obj, rect->w, rect->h);
405 eina_rectangle_free(rect);
410 _sizing_eval(Efl_Ui_Textpath_Data *pd)
416 _textpath_ellipsis_set(Efl_Ui_Textpath_Data *pd, Eina_Bool enabled)
420 edje_object_part_text_style_user_pop(pd->text_obj, "elm.text");
423 Eina_Strbuf *buf = eina_strbuf_new();
425 eina_strbuf_append_printf(buf, "DEFAULT='ellipsis=1.0'");
426 format = eina_stringshare_add(eina_strbuf_string_get(buf));
427 eina_strbuf_free(buf);
428 edje_object_part_text_style_user_push(pd->text_obj, "elm.text", format);
433 _ellipsis_set(Efl_Ui_Textpath_Data *pd)
435 if (!pd->text_obj) return;
437 Evas_Coord w = 0, h = 0;
438 Eina_Bool is_ellipsis = EINA_FALSE;
439 const Evas_Object *tb;
441 tb = edje_object_part_object_get(pd->text_obj, "elm.text");
442 evas_object_textblock_size_native_get(tb, &w, &h);
443 evas_object_size_hint_min_set(pd->text_obj, w, h);
446 if (w > pd->total_length)
448 is_ellipsis = EINA_TRUE;
449 w = pd->total_length;
452 evas_object_resize(pd->text_obj, w, h);
453 _textpath_ellipsis_set(pd, is_ellipsis);
457 //_path_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
458 _path_changed_cb(void *data,
459 Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
460 void *event_info EINA_UNUSED)
462 EFL_UI_TEXTPATH_DATA_GET(data, sd);
464 _path_data_get(data, sd, EINA_TRUE);
471 _textpath_text_set_internal(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part EINA_UNUSED, const char *text)
473 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
474 Eina_Bool ret = EINA_TRUE;
476 if (!text) text = "";
477 //ret = edje_object_part_text_set(pd->text_obj, part, text);
478 ret = edje_object_part_text_set(pd->text_obj, "elm.text", text);
485 _efl_ui_textpath_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
492 _efl_ui_textpath_elm_layout_sizing_eval(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
498 _efl_ui_textpath_evas_object_smart_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
504 //_efl_ui_textpath_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Textpath_Data *priv)
505 _efl_ui_textpath_evas_object_smart_add(Eo *obj, Efl_Ui_Textpath_Data *priv)
507 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
509 eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
510 elm_widget_sub_object_parent_add(obj);
512 priv->text_obj = edje_object_add(evas_object_evas_get(obj));
513 elm_widget_theme_object_set(obj, priv->text_obj, "textpath", "base",
514 elm_widget_style_get(obj));
515 evas_object_size_hint_weight_set(priv->text_obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
516 evas_object_size_hint_align_set(priv->text_obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
517 evas_object_show(priv->text_obj);
519 evas_object_smart_member_add(priv->text_obj, obj);
520 elm_widget_sub_object_add(obj, priv->text_obj);
522 //efl_event_callback_add(obj, EFL_GFX_PATH_EVENT_CHANGED, _path_changed_cb, obj);
523 eo_do(obj, eo_event_callback_add
524 (EFL_GFX_PATH_CHANGED, _path_changed_cb, obj));
528 _efl_ui_textpath_class_constructor(Eo_Class *klass)
530 evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
533 //EOLIAN static Efl_Object *
534 //_efl_ui_textpath_efl_object_constructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
536 _efl_ui_textpath_eo_base_constructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
538 //obj = efl_constructor(efl_super(obj, MY_CLASS));
539 obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
540 pd->autofit = EINA_TRUE;
541 pd->slice_no = SLICE_DEFAULT_NO;
542 pd->direction = EFL_UI_TEXTPATH_DIRECTION_CW;
548 //_efl_ui_textpath_efl_object_destructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
549 _efl_ui_textpath_eo_base_destructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
551 Efl_Ui_Textpath_Segment *seg;
553 if (pd->text) free(pd->text);
554 if (pd->text_obj) evas_object_del(pd->text_obj);
555 EINA_INLIST_FREE(pd->segments, seg)
557 pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
561 //efl_destructor(efl_super(obj, MY_CLASS));
562 eo_do_super(obj, MY_CLASS, eo_destructor());
565 EOLIAN static Eina_Bool
566 _efl_ui_textpath_elm_layout_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
568 return _textpath_text_set_internal(obj, pd, part, text);
571 EOLIAN static const char *
572 _efl_ui_textpath_elm_layout_text_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, const char *part)
574 return edje_object_part_text_get(pd->text_obj, part);
578 EOLIAN static Eina_Bool
579 _efl_ui_textpath_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
581 return _textpath_text_set_internal(obj, pd, part, text);
584 EOLIAN static const char *
585 _efl_ui_textpath_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, const char *part)
587 return edje_object_part_text_get(pd->text_obj, part);
591 _efl_ui_textpath_efl_text_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *text)
593 _textpath_text_set_internal(obj, pd, "elm.text", text);
596 EOLIAN static const char *
597 _efl_ui_textpath_efl_text_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
599 return edje_object_part_text_get(pd->text_obj, "elm.text");
602 //EOLIAN static Efl_Ui_Theme_Apply
603 EOLIAN static Elm_Theme_Apply
604 _efl_ui_textpath_elm_widget_theme_apply(Eo *obj, Efl_Ui_Textpath_Data *pd)
606 Elm_Theme_Apply ret = ELM_THEME_APPLY_FAILED;
608 eo_do_super(obj, MY_CLASS, ret = elm_obj_widget_theme_apply());
609 if (!ret) return ELM_THEME_APPLY_FAILED;
611 elm_widget_theme_object_set(obj, pd->text_obj, "textpath", "base",
612 elm_widget_style_get(obj));
620 //_efl_ui_textpath_evas_object_position_set(Eo *obj, Efl_Ui_Textpath_Data *pd, Evas_Coord x, Evas_Coord y)
621 _efl_ui_textpath_evas_object_smart_move(Eo *obj, Efl_Ui_Textpath_Data *pd, Evas_Coord x, Evas_Coord y)
623 eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
624 _path_data_get(obj, pd, EINA_FALSE);
630 _efl_ui_textpath_evas_object_resize(Eo *obj, Efl_Ui_Textpath_Data *pd EINA_UNUSED, Evas_Coord w, Evas_Coord h)
632 eo_do_super(obj, MY_CLASS, evas_object_resize(w, h));
636 _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)
638 if (pd->circle.x == x && pd->circle.y == y &&
639 pd->circle.radius == radius &&
640 pd->circle.start_angle == start_angle &&
641 pd->direction == direction &&
642 _map_point_calc(pd) > 0)
649 pd->circle.radius = radius;
650 pd->circle.start_angle = start_angle;
651 pd->direction = direction;
653 eo_do(obj, efl_gfx_shape_reset());
654 if (direction == EFL_UI_TEXTPATH_DIRECTION_CW)
656 eo_do(obj, efl_gfx_shape_append_arc(x - radius, y - radius, radius * 2,
657 radius * 2, start_angle, -360));
661 eo_do(obj, efl_gfx_shape_append_arc(x - radius, y - radius, radius * 2,
662 radius * 2, start_angle, 360));
668 EOLIAN static Eina_Bool
669 _efl_ui_textpath_autofit_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
675 _efl_ui_textpath_autofit_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool autofit)
677 if (pd->autofit == autofit) return;
678 pd->autofit = autofit;
683 _efl_ui_textpath_slice_number_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
689 _efl_ui_textpath_slice_number_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, int slice_no)
691 if (pd->slice_no == slice_no) return;
692 pd->slice_no = slice_no;
697 _efl_ui_textpath_ellipsis_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool ellipsis)
699 if (pd->ellipsis == ellipsis) return;
700 pd->ellipsis = ellipsis;
706 EOLIAN static Eina_Bool
707 _efl_ui_textpath_ellipsis_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
713 //ELM_PART_OVERRIDE(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
714 //ELM_PART_OVERRIDE_TEXT_SET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
715 //ELM_PART_OVERRIDE_TEXT_GET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
716 //#include "efl_ui_textpath_internal_part.eo.c"
720 elm_textpath_add(Evas_Object *parent)
722 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
723 Evas_Object *obj = eo_add(MY_CLASS, parent);
728 #define EFL_UI_TEXTPATH_EXTRA_OPS \
729 EFL_CANVAS_GROUP_ADD_OPS(efl_ui_textpath)
731 #include "efl_ui_textpath.eo.c"