summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiep Ha <thiepha@gmail.com>2017-08-25 22:27:33 +0900
committerThiep Ha <thiepha@gmail.com>2017-08-25 22:27:33 +0900
commite056726bcca90159686fb11b6fa4720d030b0ae8 (patch)
treeae2891cd788f6196225200ae072f398a02dca8fd
parentaf1f4157f244f84169dc9c18785041278476f116 (diff)
downloadefl-devs/thiep/top1.tar.gz
implementationdevs/thiep/top1
-rw-r--r--data/elementary/themes/Makefile.am1
-rw-r--r--data/elementary/themes/default.edc2
-rw-r--r--data/elementary/themes/edc/elm/textpath.edc43
-rw-r--r--src/Makefile_Elementary.am4
-rw-r--r--src/bin/elementary/test.c2
-rwxr-xr-xsrc/bin/elementary/test_efl_ui_textpathbin0 -> 18720 bytes
-rw-r--r--src/bin/elementary/test_ui_textpath.c59
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/efl_ui_textpath.c765
-rw-r--r--src/lib/elementary/efl_ui_textpath.eo62
-rw-r--r--src/lib/elementary/efl_ui_textpath_internal_part.eo8
11 files changed, 947 insertions, 0 deletions
diff --git a/data/elementary/themes/Makefile.am b/data/elementary/themes/Makefile.am
index d7632d7641..ab354a0e9c 100644
--- a/data/elementary/themes/Makefile.am
+++ b/data/elementary/themes/Makefile.am
@@ -146,6 +146,7 @@ elementary/themes/edc/elm/separator.edc \
elementary/themes/edc/elm/slider.edc \
elementary/themes/edc/elm/slideshow.edc \
elementary/themes/edc/elm/spinner.edc \
+elementary/themes/edc/elm/textpath.edc \
elementary/themes/edc/elm/thumb.edc \
elementary/themes/edc/elm/toolbar.edc \
elementary/themes/edc/elm/tooltip.edc \
diff --git a/data/elementary/themes/default.edc b/data/elementary/themes/default.edc
index 936df6b321..2a28c4a647 100644
--- a/data/elementary/themes/default.edc
+++ b/data/elementary/themes/default.edc
@@ -74,6 +74,8 @@ collections {
#include "edc/elm/cursor.edc"
#include "edc/elm/code.edc"
#include "edc/elm/ews.edc"
+#include "edc/elm/textpath.edc"
+
// desktop in general
#include "edc/wallpaper.edc"
diff --git a/data/elementary/themes/edc/elm/textpath.edc b/data/elementary/themes/edc/elm/textpath.edc
new file mode 100644
index 0000000000..3a7309f8db
--- /dev/null
+++ b/data/elementary/themes/edc/elm/textpath.edc
@@ -0,0 +1,43 @@
+group { name: "elm/textpath/base/default";
+alias: "elm/textpath/text/default";
+ styles {
+ style { name: "textpath_style";
+ base: "font="FN" font_size=16 text_class=tb_plain wrap=none align=left color=#ffffffff style=shadow,bottom shadow_color=#00000080";
+ tag: "br" "\n";
+ tag: "b" "+ font="FNBD" text_class=tb_light";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ }
+ parts {
+ part { name: "test";
+ type: SPACER;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ //color: 255 255 0 100;
+ //min: 1 1;
+ //max: 0 0;
+ }
+ }
+ part { name: "elm.swallow.background";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ }
+ }
+ part { name: "elm.text";
+ type: TEXTBLOCK;
+ scale: 1;
+ description { state: "default" 0.0;
+ align: 0.0 0.0;
+ text {
+ style: "textpath_style";
+ min: 0 1;
+ align: 0.0 0.5;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index a99b24d37e..ad50ab466b 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -133,6 +133,8 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_focus_manager_root_focus.eo \
lib/elementary/efl_ui_focus_object.eo \
lib/elementary/efl_ui_focus_user.eo \
+ lib/elementary/efl_ui_textpath.eo \
+ lib/elementary/efl_ui_textpath_internal_part.eo \
$(NULL)
# Private classes (not exposed or shipped)
@@ -690,6 +692,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_focus_manager_sub.c \
lib/elementary/efl_ui_focus_object.c \
lib/elementary/efl_ui_focus_manager_root_focus.c \
+ lib/elementary/efl_ui_textpath.c \
$(NULL)
@@ -860,6 +863,7 @@ bin/elementary/test_transit_bezier.c \
bin/elementary/test_ui_box.c \
bin/elementary/test_ui_clock.c \
bin/elementary/test_ui_grid.c \
+bin/elementary/test_ui_textpath.c \
bin/elementary/test_video.c \
bin/elementary/test_weather.c \
bin/elementary/test_web.c \
diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index 85b7b58318..4e8f76e539 100644
--- a/src/bin/elementary/test.c
+++ b/src/bin/elementary/test.c
@@ -316,6 +316,7 @@ void test_gfx_filters(void *data, Evas_Object *obj, void *event_info);
void test_evas_snapshot(void *data, Evas_Object *obj, void *event_info);
void test_evas_map(void *data, Edje_Object *obj, void *event_info);
void test_efl_gfx_map(void *data, Edje_Object *obj, void *event_info);
+void test_ui_textpath(void *data, Edje_Object *obj, void *event_info);
Evas_Object *win, *tbx; // TODO: refactoring
void *tt;
@@ -970,6 +971,7 @@ add_tests:
ADD_TEST(NULL, "Text", "Label Wrap", test_label_wrap);
ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis);
ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji);
+ ADD_TEST(NULL, "Text", "Text Path", test_ui_textpath);
//------------------------------//
ADD_TEST(NULL, "Stored Surface Buffer", "Launcher", test_launcher);
diff --git a/src/bin/elementary/test_efl_ui_textpath b/src/bin/elementary/test_efl_ui_textpath
new file mode 100755
index 0000000000..43f3b14429
--- /dev/null
+++ b/src/bin/elementary/test_efl_ui_textpath
Binary files differ
diff --git a/src/bin/elementary/test_ui_textpath.c b/src/bin/elementary/test_ui_textpath.c
new file mode 100644
index 0000000000..f565d90aa3
--- /dev/null
+++ b/src/bin/elementary/test_ui_textpath.c
@@ -0,0 +1,59 @@
+#include "test.h"
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+
+#define WIDTH 800
+#define HEIGHT 400
+
+void
+test_ui_textpath(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Evas_Object *win, *txtpath;
+
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+ win = elm_win_util_standard_add("efl.ui.textpath", "TextPath test");
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ txtpath = efl_add(EFL_UI_TEXTPATH_CLASS, win);
+ efl_ui_textpath_autofit_set(txtpath, EINA_TRUE);
+
+ //efl_text_set(txtpath, "abcdef and more you can see from this test");
+ //efl_text_set(txtpath, "abcd&lt;efghi&gt;jklm");
+ Eo *part = efl_part(txtpath, "elm.text");
+ efl_text_set(part, "abcdef more");
+ //efl_text_set(txtpath, "abcd&lt;eghi&gt;j");
+ //elm_object_text_set(txtpath, "abcd&lt;eghi&gt;j");
+ //efl_text_set(txtpath, "abcd&lt;eghi&gt;j more and more, so long to make it ellipsis? No, it is not enough, want to see more?xy");
+
+ efl_ui_textpath_circle_set(txtpath, 0, 0, 100, 180, EFL_UI_TEXTPATH_DIRECTION_CCW);
+ //efl_gfx_path_append_circle(txtpath, 200, 200, 100);
+
+ //efl_gfx_path_append_arc(txtpath, 0, 0, 100, 100, 0, -90);
+ //efl_gfx_path_append_line_to(txtpath, 100, 150);
+
+ //efl_gfx_path_append_move_to(txtpath, 200, 300);
+ //efl_gfx_path_append_line_to(txtpath, 300, 350);
+
+ //efl_gfx_path_append_move_to(txtpath, 100, 100);
+ //efl_gfx_path_append_line_to(txtpath, 200, 300);
+
+ efl_ui_textpath_ellipsis_set(txtpath, EINA_TRUE);
+ //efl_ui_textpath_autofit_set(txtpath, EINA_FALSE);
+ efl_gfx_geometry_set(txtpath, 120, 120, 200, 200);
+ efl_gfx_visible_set(txtpath, EINA_TRUE);
+
+ //Geometry set/get: does not work!!!
+ Evas_Coord x, y, w, h;
+ efl_gfx_geometry_get(txtpath, &x, &y, &w, &h);
+ printf("geo: %d %d %d %d\n", x, y, w, h);
+
+ printf("text by efl: %s\n", efl_text_get(txtpath));
+ printf("text by elm: %s\n", elm_object_text_get(txtpath));
+
+ //elm_win_resize_object_add(win, txtpath);
+ efl_gfx_size_set(win, WIDTH, HEIGHT);
+ efl_gfx_visible_set(win, 1);
+}
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 08f884c1a8..f73df08558 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -150,6 +150,7 @@ EAPI extern Elm_Version *elm_version;
# include "efl_ui_focus_manager_sub.eo.h"
# include "efl_ui_focus_manager_root_focus.eo.h"
# include "efl_ui_focus_user.eo.h"
+# include <efl_ui_textpath.eo.h>
#endif
#include <elm_tooltip.h>
diff --git a/src/lib/elementary/efl_ui_textpath.c b/src/lib/elementary/efl_ui_textpath.c
new file mode 100644
index 0000000000..aa357462ac
--- /dev/null
+++ b/src/lib/elementary/efl_ui_textpath.c
@@ -0,0 +1,765 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define ELM_LAYOUT_PROTECTED
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+#include "elm_widget_layout.h"
+#include "efl_ui_textpath_internal_part.eo.h"
+#include "elm_part_helper.h"
+
+
+#define MY_CLASS EFL_UI_TEXTPATH_CLASS
+
+#define MY_CLASS_NAME "Efl.Ui.Textpath"
+#define MY_CLASS_NAME_LEGACY "elm_textpath"
+
+#define SLICE_MAX 200
+#define SLICE_DEFAULT_NO 99
+
+typedef struct _Efl_Ui_Textpath_Point Efl_Ui_Textpath_Point;
+typedef struct _Efl_Ui_Textpath_Line Efl_Ui_Textpath_Line;
+typedef struct _Efl_Ui_Textpath_Segment Efl_Ui_Textpath_Segment;
+typedef struct _Efl_Ui_Textpath_Data Efl_Ui_Textpath_Data;
+
+struct _Efl_Ui_Textpath_Point
+{
+ double x;
+ double y;
+};
+
+struct _Efl_Ui_Textpath_Line
+{
+ Efl_Ui_Textpath_Point start;
+ Efl_Ui_Textpath_Point end;
+};
+
+struct _Efl_Ui_Textpath_Segment
+{
+ EINA_INLIST;
+ int length;
+ Efl_Gfx_Path_Command_Type type;
+ union
+ {
+ Eina_Bezier bezier;
+ Efl_Ui_Textpath_Line line;
+ };
+};
+
+
+struct _Efl_Ui_Textpath_Data
+{
+ Evas_Object *content;
+ Evas_Object *text_obj;
+ char *text;
+ Evas_Object *proxy;
+ Efl_Gfx_Path *path;
+ struct {
+ double x, y;
+ double radius;
+ double start_angle;
+ } circle;
+ Efl_Ui_Textpath_Direction direction;
+ int slice_no;
+ Eina_Bool autofit;
+ Eina_Bool ellipsis;
+
+ Eina_Inlist *segments;
+ int total_length;
+};
+
+#define EFL_UI_TEXTPATH_DATA_GET(o, sd) \
+ Efl_Ui_Textpath_Data *sd = efl_data_scope_get(o, EFL_UI_TEXTPATH_CLASS)
+
+static inline double
+_deg_to_rad(double angle)
+{
+ return angle / 180 * M_PI;
+}
+
+static inline void
+_transform_coord(double x, double y, double rad, double cx, double cy,
+ int *tx, int *ty)
+{
+ if (tx) *tx = (int)(x * cos(rad) - y * sin(rad) + cx);
+ if (ty) *ty = (int)(x * sin(rad) + y * cos(rad) + cy);
+}
+
+static void
+_textpath_ellipsis_set(Efl_Ui_Textpath_Data *pd, Eina_Bool enabled)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ const char *format;
+
+ if (enabled)
+ eina_strbuf_append_printf(buf, "DEFAULT='ellipsis=1.0'");
+ else
+ eina_strbuf_append_printf(buf, "DEFAULT='ellipsis=0.0'");
+ format = eina_stringshare_add(eina_strbuf_string_get(buf));
+ eina_strbuf_free(buf);
+ edje_object_part_text_style_user_pop(pd->text_obj, "elm.text");
+ edje_object_part_text_style_user_push(pd->text_obj, "elm.text", format);
+ ERR("set format: %s", format);
+}
+
+
+static void
+_segment_draw(Efl_Ui_Textpath_Data *pd, int slice_no, double slice_len, int w1, int w2, int cmp, Evas_Map *map, Eina_Bezier bezier)
+{
+ ERR("In: slice_no: %d, slice_len: %.2f, from: %d, to: %d, cur mp: %d", slice_no, slice_len, w1, w2, cmp);
+
+ int x = 0, y = 0, w = 0, h = 0;
+ int i, len, seg_len;
+ double u0, u1, v0, v1;
+ double dist, t, dt;
+ double px, py, px2, py2;
+ double rad;
+ Eina_Vector2 vec, nvec, vec0, vec1, vec2, vec3;
+ Eina_Matrix2 mat;
+
+ len = w2 - w1;
+ efl_gfx_size_get(pd->text_obj, &w, &h);
+ seg_len = eina_bezier_length_get(&bezier);
+ if (pd->autofit)
+ dt = len / (seg_len * (double) slice_no);
+ else
+ dt = 1.0 / (double) slice_no;
+ dist = len / (double)slice_no;
+ ERR("slice_no: %d, distance: %.1f", slice_no, dist);
+ //Compute Beziers.
+
+ //length = eina_bezier_length_get(&bezier);
+ rad = _deg_to_rad(90);
+ eina_matrix2_values_set(&mat, cos(rad), -sin(rad), sin(rad), cos(rad));
+
+ //index 0: v0, v3
+ eina_bezier_values_get(&bezier, NULL, NULL, NULL, NULL, NULL, NULL, &px2, &py2);
+ t = 0;
+ eina_bezier_point_at(&bezier, t, &px, &py);
+ eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
+
+ vec.x = (px2 - px);
+ vec.y = (py2 - py);
+ eina_vector2_normalize(&nvec, &vec);
+
+ eina_vector2_transform(&vec, &mat, &nvec);
+ eina_vector2_normalize(&nvec, &vec);
+ eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
+
+ vec1.x = (vec.x + px);
+ vec1.y = (vec.y + py);
+ vec2.x = (-vec.x + px);
+ vec2.y = (-vec.y + py);
+
+ //add points to map
+ for (i = 0; i < slice_no; i++)
+ {
+ //v0, v3
+ vec0.x = vec1.x;
+ vec0.y = vec1.y;
+ vec3.x = vec2.x;
+ vec3.y = vec2.y;
+
+ //v1, v2
+ t = ((double) (i + 1) * dt);
+ eina_bezier_point_at(&bezier, t, &px, &py);
+ eina_bezier_point_at(&bezier, t + dt, &px2, &py2);
+
+ vec.x = (px2 - px);
+ vec.y = (py2 - py);
+ eina_vector2_normalize(&nvec, &vec);
+
+ eina_vector2_transform(&vec, &mat, &nvec);
+ eina_vector2_normalize(&nvec, &vec);
+ eina_vector2_scale(&vec, &nvec, ((double) h) * 0.5);
+
+ vec1.x = (vec.x + px);
+ vec1.y = (vec.y + py);
+ vec2.x = (-vec.x + px);
+ vec2.y = (-vec.y + py);
+
+
+ evas_map_point_coord_set(map, cmp + i * 4, (int) vec0.x + x, (int) vec0.y + y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 1, (int) vec1.x + x, (int) vec1.y + y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 2, (int) vec2.x + x, (int) vec2.y + y, 0);
+ evas_map_point_coord_set(map, cmp + i * 4 + 3, (int) vec3.x + x, (int) vec3.y + y, 0);
+
+ //UV
+ u0 = w1 + i * dist;
+ u1 = u0 + dist;
+ v0 = (double) 0;
+ v1 = (double) h;
+
+ evas_map_point_image_uv_set(map, cmp + i * 4, u0, v0);
+ evas_map_point_image_uv_set(map, cmp + i * 4 + 1, u1, v0);
+ evas_map_point_image_uv_set(map, cmp + i * 4 + 2, u1, v1);
+ evas_map_point_image_uv_set(map, cmp + i * 4 + 3, u0, v1);
+
+ if (i < 3)
+ {
+ ERR("map(%d): %d %d :: %d %d :: %d %d :: %d %d", cmp + i*4, (int)vec0.x + x, (int)vec0.y + y, (int)vec1.x + x, (int)vec1.y + y, (int)vec2.x + x, (int)vec2.y + y, (int)vec3.x + x, (int)vec3.y + y);
+ ERR("map uv: %.1f %.1f :: %.1f %.1f", u0, v0, u1, v1);
+ }
+ }
+}
+
+static void
+_text_on_line_draw(Efl_Ui_Textpath_Data *pd, int w1, int w2, int cmp, Evas_Map *map, Efl_Ui_Textpath_Line line)
+{
+ double x1, x2, y1, y2;
+ x1 = line.start.x;
+ y1 = line.start.y;
+ x2 = line.end.x;
+ y2 = line.end.y;
+ ERR("line: %.1f %.1f - %.1f %.1f", x1, y1, x2, y2);
+
+ double line_len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
+ double len = w2 - w1;
+ if (line_len > len)
+ {
+ x2 = x1 + len * (x2 - x1) / line_len;
+ y2 = y1 + len * (y2 - y1) / line_len;
+ ERR("new: %.1f %.1f - %.1f %.1f", x1, y1, x2, y2);
+ }
+
+ Evas_Coord x, y, w, h;
+ efl_gfx_geometry_get(pd->text_obj, &x, &y, &w, &h);
+ ERR("content geo: %d %d %d %d", x, y, w, h);
+ ERR("line geo: %.1f %.1f :: %.1f %.1f, area: %d %d, cmp: %d", x1, y1, x2, y2, w1, w2, cmp);
+
+ double sina, cosa;
+ len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
+ sina = (y2 - y1) / len;
+ cosa = (x2 - x1) / len;
+
+ h = h / 2;
+ evas_map_point_coord_set(map, cmp + 3, x1 - h * sina, y1 + h * cosa, 0);
+ evas_map_point_coord_set(map, cmp + 2, x2 - h * sina, y2 + h * cosa, 0);
+ evas_map_point_coord_set(map, cmp + 1, x2 + h * sina, y2 - h * cosa, 0);
+ evas_map_point_coord_set(map, cmp + 0, x1 + h * sina, y1 - h * cosa, 0);
+
+ h *= 2;
+ evas_map_point_image_uv_set(map, cmp + 0, w1, 0);
+ evas_map_point_image_uv_set(map, cmp + 1, w2, 0);
+ evas_map_point_image_uv_set(map, cmp + 2, w2, h);
+ evas_map_point_image_uv_set(map, cmp + 3, w1, h);
+
+}
+
+static int
+_map_point_calc(Efl_Ui_Textpath_Data *pd)
+{
+ int map_no = 0;
+ Efl_Ui_Textpath_Segment *seg;
+
+ EINA_INLIST_FOREACH(pd->segments, seg)
+ {
+ if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
+ {
+ map_no++;
+ }
+ else if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
+ {
+ int no = pd->slice_no * seg->length / (double)pd->total_length;
+ map_no += no;
+ }
+ }
+ map_no *= 4;
+
+ return map_no;
+}
+
+static void
+_text_draw(Efl_Ui_Textpath_Data *pd)
+{
+ Efl_Ui_Textpath_Segment *seg;
+ Evas_Map *map;
+ double slice_unit, slice_len;
+ int w, h, w1, w2;
+ int remained_w;
+ int total_slice;
+ int cur_map_point = 0;
+ int drawn_slice;
+
+ efl_gfx_size_get(pd->text_obj, &w, &h);
+ if (pd->autofit)
+ {
+ remained_w = w;
+ }
+ else
+ {
+ remained_w = pd->total_length;
+ }
+ slice_unit = (double)pd->slice_no / pd->total_length;
+
+ slice_len = 1.0 / slice_unit;
+ total_slice = w / slice_len + 1;
+
+ int map_no = _map_point_calc(pd);
+ ERR("map poins no: %d", map_no);
+ if (map_no == 0) return;
+ map = evas_map_new(map_no);
+
+ w1 = w2 = 0;
+ EINA_INLIST_FOREACH(pd->segments, seg)
+ {
+ int len = seg->length;
+ if (!pd->autofit)
+ {
+ len = (double)seg->length * w / (double)pd->total_length;
+ ERR("len: %d", len);
+ }
+ ERR("w: %d, total_length: %d, seg length: %d, len: %d", w, pd->total_length, seg->length, len);
+ if (remained_w <= 0)
+ break;
+ w2 = w1 + len;
+ if (w2 > w)
+ w2 = w;
+ if (seg->type == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
+ {
+ drawn_slice += 1;
+ _text_on_line_draw(pd, w1, w2, cur_map_point, map, seg->line);
+ cur_map_point += 4;
+ }
+ else
+ {
+ int slice_no = len * slice_unit + 1;
+ slice_no = pd->slice_no * seg->length / (double)pd->total_length;
+ slice_len = seg->length / slice_no;
+ if (remained_w == 0)
+ slice_no = total_slice - drawn_slice;
+ drawn_slice += slice_no;
+ _segment_draw(pd, slice_no, slice_len, w1, w2, cur_map_point, map, seg->bezier);
+ cur_map_point += slice_no * 4;
+ }
+ w1 = w2;
+ remained_w -= len;
+ }
+ evas_object_map_enable_set(pd->text_obj, EINA_TRUE);
+ evas_object_map_set(pd->text_obj, map);
+ evas_map_free(map);
+}
+
+
+static void
+_path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd, Eina_Bool set_min)
+{
+ ERR("In");
+
+ const Efl_Gfx_Path_Command_Type *cmd;
+ const double *points;
+ Efl_Ui_Textpath_Segment *seg;
+
+ //delete previous segment list
+ EINA_INLIST_FREE(pd->segments, seg)
+ {
+ pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
+ free(seg);
+ }
+
+ Evas_Coord x, y;
+ efl_gfx_position_get(obj, &x, &y);
+
+ pd->total_length = 0;
+ efl_gfx_path_get(obj, &cmd, &points);
+ if (cmd)
+ {
+ ERR("cmd exist");
+ int pos = -1;
+ Eina_Rectangle *rect = eina_rectangle_new(0, 0, 0, 0);
+ while (*cmd != EFL_GFX_PATH_COMMAND_TYPE_END)
+ {
+ double px0, py0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1;
+ ERR("cmd: %d", *cmd);
+ if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO)
+ {
+ pos++;
+ px0 = points[pos] + x;
+ pos++;
+ py0 = points[pos] + y;
+ }
+ else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO)
+ {
+ Eina_Bezier bz;
+
+ pos++;
+ ctrl_x0 = points[pos] + x;
+ pos++;
+ ctrl_y0 = points[pos] + y;
+ pos++;
+ ctrl_x1 = points[pos] + x;
+ pos++;
+ ctrl_y1 = points[pos] + y;
+ pos++;
+ px1 = points[pos] + x;
+ pos++;
+ py1 = points[pos] + y;
+
+ eina_bezier_values_set(&bz, px0, py0, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1, px1, py1);
+ seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
+ if (!seg)
+ {
+ ERR("Failed to allocate segment");
+ px0 = px1;
+ py0 = py1;
+ continue;
+ }
+ seg->length = eina_bezier_length_get(&bz);
+ seg->bezier = bz;
+ seg->type = EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO;
+ pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
+ pd->total_length += seg->length;
+
+ //move points
+ px0 = px1;
+ py0 = py1;
+
+ double bx, by, bw, bh;
+ eina_bezier_bounds_get(&bz, &bx, &by, &bw, &bh);
+ Eina_Rectangle *brect = eina_rectangle_new(bx, by, bw, bh);
+ eina_rectangle_union(rect, brect);
+ eina_rectangle_free(brect);
+ }
+ else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_LINE_TO)
+ {
+ pos++;
+ px1 = points[pos] + x;
+ pos++;
+ py1 = points[pos] + y;
+ ERR("line: %.1f %.1f :: %.1f %.1f", px0, py0, px1, py1);
+
+ seg = malloc(sizeof(Efl_Ui_Textpath_Segment));
+ if (!seg)
+ {
+ ERR("Failed to allocate segment");
+ px0 = px1;
+ py0 = py1;
+ }
+ seg->type = EFL_GFX_PATH_COMMAND_TYPE_LINE_TO;
+ seg->line.start.x = px0;
+ seg->line.start.y = py0;
+ seg->line.end.x = px1;
+ seg->line.end.y = py1;
+ seg->length = sqrt((px1 - px0)*(px1 - px0) + (py1 - py0)*(py1 - py0));
+ pd->segments = eina_inlist_append(pd->segments, EINA_INLIST_GET(seg));
+ pd->total_length += seg->length;
+
+ Eina_Rectangle *lrect = eina_rectangle_new(px0, py0, px1 - px0, py1 - py0);
+ eina_rectangle_union(rect, lrect);
+ eina_rectangle_free(lrect);
+ }
+ cmd++;
+ }
+ if (set_min)
+ {
+ evas_object_size_hint_min_set(obj, rect->w, rect->h);
+ ERR("set min size: %d %d %d %d", rect->x, rect->y, rect->w, rect->h);
+ }
+ eina_rectangle_free(rect);
+ }
+}
+
+static void
+_sizing_eval(Efl_Ui_Textpath_Data *pd)
+{
+ //_path_data_get(obj, pd);
+ _text_draw(pd);
+}
+
+static void
+_ellipsis_set(Efl_Ui_Textpath_Data *pd)
+{
+ if (!pd->text_obj) return;
+
+ Evas_Coord w = 0, h = 0;
+ Eina_Bool is_ellipsis = EINA_FALSE;
+
+ efl_gfx_size_get(pd->text_obj, &w, &h);
+ if (pd->ellipsis)
+ {
+ if (w > pd->total_length)
+ {
+ is_ellipsis = EINA_TRUE;
+ w = pd->total_length;
+ ERR("enable ellipsis");
+ }
+ }
+ evas_object_resize(pd->text_obj, w, h);
+ _textpath_ellipsis_set(pd, is_ellipsis);
+}
+
+static void
+_path_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ ERR("Path changed");
+ EFL_UI_TEXTPATH_DATA_GET(data, sd);
+
+ _path_data_get(data, sd, EINA_TRUE);
+}
+
+/*EOLIAN static void
+ _efl_ui_textpath_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Textpath_Data *pd)
+ {
+ ERR("In");
+//_sizing_eval(pd);
+}*/
+
+static Eina_Bool
+_textpath_text_set_internal(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
+{
+ ERR("in: part: %s, text: %s", part, text);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+ Eina_Bool int_ret = EINA_TRUE;
+
+ if (!text) text = "";
+ //set format
+ //_textpath_format_set(wd->resize_obj, sd->format);
+
+ efl_text_set(efl_part(efl_super(obj, MY_CLASS), part), text);
+
+ edje_object_part_text_set(pd->text_obj, "elm.text", text);
+ //elm_layout_text_set(pd->text_obj, NULL, text);
+ if (int_ret)
+ {
+ //elm_obj_layout_sizing_eval(obj);
+ }
+ //
+ const Evas_Object *tb;
+ Evas_Coord tb_w = 0, tb_h = 0;
+ tb = edje_object_part_object_get(pd->text_obj, "elm.text");
+ evas_object_textblock_size_native_get(tb, &tb_w, &tb_h);
+ //??? layout sizing_eval also does min set based on the edje size calc
+ evas_object_size_hint_min_set(pd->text_obj, tb_w, tb_h);
+ evas_object_resize(pd->text_obj, tb_w, tb_h);
+ ERR("tb size: %d %d", tb_w, tb_h);
+ //
+
+ _ellipsis_set(pd);
+ //elm_obj_layout_sizing_eval(obj);
+
+ return int_ret;
+}
+
+
+EOLIAN static Eina_Bool
+_efl_ui_textpath_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *part, const char *text)
+{
+ ERR("in: part: %s, text: %s", part, text);
+ return _textpath_text_set_internal(obj, pd, part, text);
+}
+
+EOLIAN static const char *
+_efl_ui_textpath_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, const char *part)
+{
+ return elm_layout_text_get(pd->text_obj, part);
+}
+
+EOLIAN static void
+_efl_ui_textpath_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Textpath_Data *priv)
+{
+ ERR("In");
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ efl_canvas_group_add(efl_super(obj, MY_CLASS));
+ elm_widget_sub_object_parent_add(obj);
+
+ //if (!elm_layout_theme_set(obj, "textpath", "base", elm_widget_style_get(obj)))
+ // CRI("Failed to set layout");
+
+ //elm_layout_sizing_eval(obj);
+
+ priv->text_obj = edje_object_add(evas_object_evas_get(obj));
+ elm_widget_theme_object_set(obj, priv->text_obj, "textpath", "base",
+ elm_widget_style_get(obj));
+ edje_object_part_text_set(priv->text_obj, "elm.text", "test text");
+ evas_object_size_hint_weight_set(priv->text_obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(priv->text_obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(priv->text_obj);
+
+ evas_object_smart_member_add(priv->text_obj, obj);
+ elm_widget_sub_object_add(obj, priv->text_obj);
+
+ efl_event_callback_add(obj, EFL_GFX_PATH_EVENT_CHANGED, _path_changed_cb, obj);
+}
+
+EOLIAN static void
+_efl_ui_textpath_class_constructor(Efl_Class *klass)
+{
+ ERR("In");
+ evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
+}
+
+EOLIAN static Efl_Object *
+_efl_ui_textpath_efl_object_constructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
+{
+ ERR("in");
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+ pd->autofit = EINA_TRUE;
+ pd->slice_no = SLICE_DEFAULT_NO;
+ pd->direction = EFL_UI_TEXTPATH_DIRECTION_CW;
+
+ return obj;
+}
+
+EOLIAN static void
+_efl_ui_textpath_efl_object_destructor(Eo *obj, Efl_Ui_Textpath_Data *pd)
+{
+ Efl_Ui_Textpath_Segment *seg;
+
+ if (pd->content) evas_object_del(pd->content);
+ if (pd->text) free(pd->text);
+ if (pd->text_obj) evas_object_del(pd->text_obj);
+ EINA_INLIST_FREE(pd->segments, seg)
+ {
+ pd->segments = eina_inlist_remove(pd->segments, EINA_INLIST_GET(seg));
+ free(seg);
+ }
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static void
+_efl_ui_textpath_efl_text_text_set(Eo *obj, Efl_Ui_Textpath_Data *pd, const char *text)
+{
+ _textpath_text_set_internal(obj, pd, "elm.text", text);
+}
+
+EOLIAN static const char *
+_efl_ui_textpath_efl_text_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
+{
+ return elm_layout_text_get(pd->text_obj, "elm.text");
+}
+
+EOLIAN static Efl_Ui_Theme_Apply
+_efl_ui_textpath_elm_widget_theme_apply(Eo *obj, Efl_Ui_Textpath_Data *pd)
+{
+ ERR("theme set");
+ Efl_Ui_Theme_Apply ret = EFL_UI_THEME_APPLY_FAILED;
+
+ ret = elm_obj_widget_theme_apply(efl_super(obj, MY_CLASS));
+ if (!ret) return EFL_UI_THEME_APPLY_FAILED;
+
+ elm_widget_theme_object_set(obj, pd->text_obj, "textpath", "base",
+ elm_widget_style_get(obj));
+ //need to set ellipsis again
+
+ return ret;
+}
+
+EOLIAN static void
+_efl_ui_textpath_efl_gfx_position_set(Eo *obj, Efl_Ui_Textpath_Data *pd, Evas_Coord x, Evas_Coord y)
+{
+ ERR("obj: %p,text_obj: %p, set position: textpath: %d %d", obj, pd->text_obj, x, y);
+ efl_gfx_position_set(efl_super(obj, MY_CLASS), x, y);
+ if (pd->text_obj)
+ {
+ //ERR("move text_obj to: %d %d", x, y);
+ //efl_gfx_position_set(pd->text_obj, x, y);
+ }
+
+ _path_data_get(obj, pd, EINA_FALSE);
+ _text_draw(pd);
+}
+
+EOLIAN static void
+_efl_ui_textpath_efl_gfx_size_set(Eo *obj, Efl_Ui_Textpath_Data *pd EINA_UNUSED, Evas_Coord w, Evas_Coord h)
+{
+ ERR("size set: %d %d", w, h);
+ efl_gfx_size_set(efl_super(obj, MY_CLASS), w, h);
+}
+
+EOLIAN static void
+_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)
+{
+ if (pd->circle.x == x && pd->circle.y == y &&
+ pd->circle.radius == radius &&
+ pd->circle.start_angle == start_angle &&
+ pd->direction == direction)
+ {
+ ERR("Same circle");
+ return;
+ }
+ pd->circle.x = x;
+ pd->circle.y = y;
+ pd->circle.radius = radius;
+ pd->circle.start_angle = start_angle;
+ pd->direction = direction;
+
+ if (direction == EFL_UI_TEXTPATH_DIRECTION_CW)
+ {
+ efl_gfx_path_append_arc(obj, x - radius, y - radius, radius * 2,
+ radius * 2, start_angle, -360);
+ }
+ else
+ {
+ efl_gfx_path_append_arc(obj, x - radius, y - radius, radius * 2,
+ radius * 2, start_angle, 360);
+ }
+
+
+ if (pd->content)
+ efl_gfx_size_set(pd->content, 2 * radius, 2 * radius);
+
+ _sizing_eval(pd);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_textpath_autofit_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
+{
+ return pd->autofit;
+}
+
+EOLIAN static void
+_efl_ui_textpath_autofit_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool autofit)
+{
+ if (pd->autofit == autofit) return;
+ pd->autofit = autofit;
+ _sizing_eval(pd);
+}
+
+EOLIAN static int
+_efl_ui_textpath_slice_number_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
+{
+ return pd->slice_no;
+}
+
+EOLIAN static void
+_efl_ui_textpath_slice_number_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, int slice_no)
+{
+ if (pd->slice_no == slice_no) return;
+ pd->slice_no = slice_no;
+ _sizing_eval(pd);
+}
+
+EOLIAN static void
+_efl_ui_textpath_ellipsis_set(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd, Eina_Bool ellipsis)
+{
+ if (pd->ellipsis == ellipsis) return;
+ pd->ellipsis = ellipsis;
+
+ _ellipsis_set(pd);
+
+ _sizing_eval(pd);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_textpath_ellipsis_get(Eo *obj EINA_UNUSED, Efl_Ui_Textpath_Data *pd)
+{
+ return pd->ellipsis;
+}
+
+
+/* Efl.Part begin */
+ELM_PART_OVERRIDE(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
+ELM_PART_OVERRIDE_TEXT_SET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
+ELM_PART_OVERRIDE_TEXT_GET(efl_ui_textpath, EFL_UI_TEXTPATH, EFL_UI_LAYOUT, Efl_Ui_Textpath_Data, Elm_Part_Data)
+#include "efl_ui_textpath_internal_part.eo.c"
+/* Efl.Part end */
+
+#define EFL_UI_TEXTPATH_EXTRA_OPS \
+ EFL_CANVAS_GROUP_ADD_OPS(efl_ui_textpath)
+
+#include "efl_ui_textpath.eo.c"
diff --git a/src/lib/elementary/efl_ui_textpath.eo b/src/lib/elementary/efl_ui_textpath.eo
new file mode 100644
index 0000000000..0ad61a455d
--- /dev/null
+++ b/src/lib/elementary/efl_ui_textpath.eo
@@ -0,0 +1,62 @@
+enum Efl.Ui.Textpath.Direction {
+ cw,
+ ccw
+}
+
+//class Efl.Ui.Textpath (Elm.Layout, Efl.Object, Efl.Text, Efl.Gfx.Path)
+class Efl.Ui.Textpath (Elm.Widget, Efl.Object, Efl.Part, Efl.Text, Efl.Gfx.Path)
+{
+ [[Efl Ui Textpath class]]
+ legacy_prefix: elm_textpath;
+ methods {
+ circle_set {
+ [[Set a circle with given center, radius, and start angle.]]
+ params {
+ @in x: double;
+ @in y: double;
+ @in radius: double;
+ @in start_angle: double;
+ @in direction: Efl.Ui.Textpath.Direction;
+ }
+ }
+ @property autofit {
+ [[The ability to fit the text within the path.
+ Set it to EINA_TRUE to let text occupy only portion
+ same as its size. Otherwise, text will occupied the whole path.
+ By default, it is EINA_TRUE.]]
+ values {
+ autofit: bool;
+ }
+ }
+ @property slice_number {
+ [[The number of slices. The larger the number of slice_num is,
+ The better the text follow the path.]]
+ values {
+ slice_no: int;
+ }
+ }
+ @property ellipsis {
+ [[Control the ellipsis behavior of the textpath.]]
+ set {
+ }
+ get {
+ }
+ values {
+ ellipsis: bool; [[To ellipsis text or not]]
+ }
+ }
+ }
+ implements {
+ class.constructor;
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ //Elm.Layout.sizing_eval;
+ Efl.Text.text {get; set;}
+ Efl.Part.part;
+ Elm.Widget.theme_apply;
+ Efl.Gfx.position { set; }
+ Efl.Gfx.size { set; }
+ }
+ events {
+ }
+}
diff --git a/src/lib/elementary/efl_ui_textpath_internal_part.eo b/src/lib/elementary/efl_ui_textpath_internal_part.eo
new file mode 100644
index 0000000000..daba6f3a33
--- /dev/null
+++ b/src/lib/elementary/efl_ui_textpath_internal_part.eo
@@ -0,0 +1,8 @@
+class Efl.Ui.Textpath.Internal.Part (Efl.Ui.Layout.Internal.Part, Efl.Text)
+{
+ [[Efl UI Textpath internal part class]]
+ data: null;
+ implements {
+ Efl.Text.text { set; get; }
+ }
+}