From bf7e05586f002aa66688c37eabcd3a44f847ee16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jul 2019 16:47:43 +0900 Subject: [PATCH] efl_ui_textpath: introduce efl_ui_textpath_circular_set() interface. Summary: This patch revises efl_ui_textpath_circle_set() interface. Current circle_set() behavior is wrongly working, it makes object minimal size with (x * 2, y * 2). Insanely, how big size if the object is far from the screen origin. Secondly, current interface requires center position, How this center position could be guranteed if user wants to put it into a container? Third, actual textpath output could be out of the textpath boundary, since the textpath is originated to middle of text height. the display boundary can be outside of the textpath geometry by (half of text height). All in all, put altogether in fix, I confirmed there is no methods without any compatibility break. This brings elm_textpath_circular_set() api introduced. @feature Reviewers: #committers, kimcinoo, jsuya Subscribers: zmike, bu5hm4n, segfaultxavi, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9260 --- src/bin/elementary/test_ui_textpath.c | 10 +- src/lib/elementary/efl_ui_textpath.c | 165 ++++++++++++++---- src/lib/elementary/efl_ui_textpath.eo | 7 +- .../elementary/efl_ui_textpath_eo.legacy.c | 5 +- .../elementary/efl_ui_textpath_eo.legacy.h | 16 ++ 5 files changed, 157 insertions(+), 46 deletions(-) diff --git a/src/bin/elementary/test_ui_textpath.c b/src/bin/elementary/test_ui_textpath.c index e4756996f3..111ebe1af4 100644 --- a/src/bin/elementary/test_ui_textpath.c +++ b/src/bin/elementary/test_ui_textpath.c @@ -6,8 +6,6 @@ #include #include -#define CX 180 -#define CY 150 #define CR 100 #define TEST_UI_TEXTPATH_LONG_TEXT "This text follows the path which you defined. This is a <long> text designed to make it ellipsis." @@ -31,7 +29,7 @@ _direction_changed_cb(void *data, const Efl_Event *event) Eina_Bool val = elm_check_selected_get(event->object); Efl_Ui_Textpath_Direction dir = val ? EFL_UI_TEXTPATH_DIRECTION_CW : EFL_UI_TEXTPATH_DIRECTION_CCW; - efl_ui_textpath_circle_set(txtpath, CX, CY, CR, angle, dir); + efl_ui_textpath_circular_set(txtpath, CR, angle, dir); } static void @@ -43,7 +41,7 @@ _angle_changed_cb(void *data, const Efl_Event *event) Eina_Bool val = elm_check_selected_get(dir_chk); Efl_Ui_Textpath_Direction dir = val ? EFL_UI_TEXTPATH_DIRECTION_CW : EFL_UI_TEXTPATH_DIRECTION_CCW; - efl_ui_textpath_circle_set(txtpath, CX, CY, CR, angle, dir); + efl_ui_textpath_circular_set(txtpath, CR, angle, dir); } static void @@ -76,7 +74,7 @@ _change_shape_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA Eina_Bool val = elm_check_selected_get(dir_chk); Efl_Ui_Textpath_Direction dir = val ? EFL_UI_TEXTPATH_DIRECTION_CW : EFL_UI_TEXTPATH_DIRECTION_CCW; - efl_ui_textpath_circle_set(txtpath, CX, CY, CR, angle, dir); + efl_ui_textpath_circular_set(txtpath, CR, angle, dir); } } @@ -109,7 +107,7 @@ test_ui_textpath(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve efl_text_set(txtpath, TEST_UI_TEXTPATH_LONG_TEXT); - efl_ui_textpath_circle_set(txtpath, CX, CY, CR, 0, EFL_UI_TEXTPATH_DIRECTION_CCW); + efl_ui_textpath_circular_set(txtpath, CR, 0, EFL_UI_TEXTPATH_DIRECTION_CCW); efl_gfx_entity_visible_set(txtpath, EINA_TRUE); path_type = 0; diff --git a/src/lib/elementary/efl_ui_textpath.c b/src/lib/elementary/efl_ui_textpath.c index c25410e1fc..aa89865a42 100644 --- a/src/lib/elementary/efl_ui_textpath.c +++ b/src/lib/elementary/efl_ui_textpath.c @@ -70,6 +70,7 @@ struct _Efl_Ui_Textpath_Data #ifdef EFL_UI_TEXTPATH_LINE_DEBUG Eina_List *lines; #endif + Eina_Bool circular : 1; //TODO: Remove this flag when elm_textpath_circle_set() is removed. }; #define EFL_UI_TEXTPATH_DATA_GET(o, sd) \ @@ -407,7 +408,7 @@ _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd) const Efl_Gfx_Path_Command_Type *cmd; const double *points; Efl_Ui_Textpath_Segment *seg; - Eina_Position2D opos; + Eina_Position2D obj_pos; EINA_INLIST_FREE(pd->segments, seg) { @@ -415,7 +416,16 @@ _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd) free(seg); } - opos = efl_gfx_entity_position_get(obj); + obj_pos = efl_gfx_entity_position_get(obj); + + /* textpath calculates boundary with the middle of text height. + this has better precise boundary than circle_set() behavior. */ + if (pd->circular) + { + Eina_Size2D text_size = efl_gfx_entity_size_get(pd->text_obj); + obj_pos.x += (text_size.h / 2); + obj_pos.y += (text_size.h / 2); + } pd->total_length = 0; efl_gfx_path_get(obj, &cmd, &points); @@ -430,9 +440,9 @@ _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd) if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO) { pos++; - px0 = points[pos] + opos.x; + px0 = points[pos] + obj_pos.x; pos++; - py0 = points[pos] + opos.y; + py0 = points[pos] + obj_pos.y; } else if (*cmd == EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO) { @@ -441,17 +451,17 @@ _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd) Eina_Rect brect; pos++; - ctrl_x0 = points[pos] + opos.x; + ctrl_x0 = points[pos] + obj_pos.x; pos++; - ctrl_y0 = points[pos] + opos.y; + ctrl_y0 = points[pos] + obj_pos.y; pos++; - ctrl_x1 = points[pos] + opos.x; + ctrl_x1 = points[pos] + obj_pos.x; pos++; - ctrl_y1 = points[pos] + opos.y; + ctrl_y1 = points[pos] + obj_pos.y; pos++; - px1 = points[pos] + opos.x; + px1 = points[pos] + obj_pos.x; pos++; - py1 = points[pos] + opos.y; + py1 = points[pos] + obj_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)); @@ -481,9 +491,9 @@ _path_data_get(Eo *obj, Efl_Ui_Textpath_Data *pd) Eina_Rect lrect; pos++; - px1 = points[pos] + opos.x; + px1 = points[pos] + obj_pos.x; pos++; - py1 = points[pos] + opos.y; + py1 = points[pos] + obj_pos.y; seg = malloc(sizeof(Efl_Ui_Textpath_Segment)); if (!seg) @@ -612,6 +622,7 @@ _path_start_angle_adjust(Eo *obj, Efl_Ui_Textpath_Data *pd) offset_angle /= 2.0; efl_gfx_path_reset(obj); + if (pd->direction == EFL_UI_TEXTPATH_DIRECTION_CW_CENTER) { efl_gfx_path_append_arc(obj, @@ -753,21 +764,22 @@ _efl_ui_textpath_efl_ui_widget_theme_apply(Eo *obj, Efl_Ui_Textpath_Data *pd) EOLIAN static void _efl_ui_textpath_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Textpath_Data *pd, Eina_Position2D pos) { - Eina_Position2D opos, diff; + Eina_Position2D ppos, diff; Efl_Ui_Textpath_Segment *seg; double sx, sy, csx, csy, cex, cey, ex, ey; - opos = efl_gfx_entity_position_get(obj); - - diff.x = pos.x - opos.x; - diff.y = pos.y - opos.y; - + ppos = efl_gfx_entity_position_get(obj); efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos); + if (ppos.x == pos.x && ppos.y == pos.y) return; + + diff.x = pos.x - ppos.x; + diff.y = pos.y - ppos.y; + EINA_INLIST_FOREACH(pd->segments, seg) { eina_bezier_values_get(&seg->bezier, &sx, &sy, &csx, &csy, - &cex, &cey, &ex, &ey); + &cex, &cey, &ex, &ey); sx += diff.x; sy += diff.y; csx += diff.x; @@ -778,53 +790,99 @@ _efl_ui_textpath_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Textpath_Data *pd, ey += diff.y; eina_bezier_values_set(&seg->bezier, sx, sy, csx, csy, - cex, cey, ex, ey); + cex, cey, ex, ey); } _text_draw(pd); } EOLIAN static void -_efl_ui_textpath_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Textpath_Data *pd EINA_UNUSED, Eina_Size2D sz) +_efl_ui_textpath_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Textpath_Data *pd EINA_UNUSED, Eina_Size2D size) { - Eina_Size2D psize = efl_gfx_entity_size_get(obj); - efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz); - if (psize.w != sz.w || psize.h != sz.h) _text_draw(pd); + Eina_Size2D psize, diff; + Efl_Ui_Textpath_Segment *seg; + double sx, sy, csx, csy, cex, cey, ex, ey; + + psize = efl_gfx_entity_size_get(obj); + efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), size); + + if (psize.w == size.w && psize.h == size.h) return; + + //TODO: Remove this condition if circle_set() is removed + if (pd->circle.radius > 0 && !pd->circular) return; + + diff.w = (size.w - psize.w) * 0.5; + diff.h = (size.h - psize.h) * 0.5; + + EINA_INLIST_FOREACH(pd->segments, seg) + { + eina_bezier_values_get(&seg->bezier, &sx, &sy, &csx, &csy, + &cex, &cey, &ex, &ey); + sx += diff.w; + sy += diff.h; + csx += diff.w; + csy += diff.h; + cex += diff.w; + cey += diff.h; + ex += diff.w; + ey += diff.h; + + eina_bezier_values_set(&seg->bezier, sx, sy, csx, csy, + cex, cey, ex, ey); + } + + _text_draw(pd); } 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) +_efl_ui_textpath_circular_set(Eo *obj, Efl_Ui_Textpath_Data *pd, double radius, double start_angle, Efl_Ui_Textpath_Direction direction) { - double sweep_length; + Eina_Size2D text_size; + double sweep_length, x, y; - if (pd->circle.x == x && pd->circle.y == y && - pd->circle.radius == radius && + if (pd->circle.radius == radius && pd->circle.start_angle == start_angle && pd->direction == direction && _map_point_calc(pd) > 0) return; - pd->circle.x = x; - pd->circle.y = y; + + Eina_Size2D obj_size = efl_gfx_entity_size_get(obj); + + //textpath min size is same to circle bounadary */ + text_size = efl_gfx_entity_size_get(pd->text_obj); + + x = (obj_size.w - text_size.h - (2 * radius)) * 0.5; + y = (obj_size.h - text_size.h - (2 * radius)) * 0.5; + + /* User leaves center position to textpath itself. + Now textpath automatically updates circle text according to + object position. */ + pd->circle.x = radius + x; + pd->circle.y = radius + y; pd->circle.radius = radius; pd->circle.start_angle = start_angle; pd->direction = direction; + pd->circular = EINA_TRUE; efl_gfx_path_reset(obj); if (direction == EFL_UI_TEXTPATH_DIRECTION_CW || direction == EFL_UI_TEXTPATH_DIRECTION_CW_CENTER) - sweep_length = -360; - else sweep_length = 360; + else + sweep_length = -360; - efl_gfx_path_append_arc(obj, x - radius, y - radius, radius * 2, + efl_gfx_path_append_arc(obj, + pd->circle.x - pd->circle.radius, + pd->circle.y - pd->circle.radius, + radius * 2, radius * 2, start_angle, sweep_length); _path_data_get(obj, pd); _path_start_angle_adjust(obj, pd); _sizing_eval(pd); - efl_gfx_hint_size_min_set(obj, EINA_SIZE2D(x * 2, y * 2)); + efl_gfx_hint_size_min_set(obj, EINA_SIZE2D((radius * 2) + text_size.h, (radius * 2) + text_size.h)); } EOLIAN static int @@ -907,5 +965,44 @@ elm_textpath_add(Evas_Object *parent) return elm_legacy_add(EFL_UI_TEXTPATH_LEGACY_CLASS, parent); } +EAPI void +elm_textpath_circle_set(Eo *obj, double x, double y, double radius, double start_angle, Efl_Ui_Textpath_Direction direction) +{ + double sweep_length; + + EFL_UI_TEXTPATH_DATA_GET(obj, pd); + + if (pd->circle.x == x && pd->circle.y == y && + pd->circle.radius == radius && + pd->circle.start_angle == start_angle && + pd->direction == direction && + _map_point_calc(pd) > 0) + return; + + pd->circle.x = x; + pd->circle.y = y; + pd->circle.radius = radius; + pd->circle.start_angle = start_angle; + pd->direction = direction; + pd->circular = EINA_FALSE; + + efl_gfx_path_reset(obj); + + if (direction == EFL_UI_TEXTPATH_DIRECTION_CW || + direction == EFL_UI_TEXTPATH_DIRECTION_CW_CENTER) + sweep_length = - 360; + else + sweep_length = 360; + + efl_gfx_path_append_arc(obj, x - radius, y - radius, radius * 2, + radius * 2, start_angle, sweep_length); + + _path_data_get(obj, pd); + _path_start_angle_adjust(obj, pd); + _sizing_eval(pd); + + efl_gfx_hint_size_min_set(obj, EINA_SIZE2D(x * 2, y * 2)); +} + #include "efl_ui_textpath_legacy_eo.c" diff --git a/src/lib/elementary/efl_ui_textpath.eo b/src/lib/elementary/efl_ui_textpath.eo index 4a56b490a3..7d834a8d0a 100644 --- a/src/lib/elementary/efl_ui_textpath.eo +++ b/src/lib/elementary/efl_ui_textpath.eo @@ -10,11 +10,10 @@ class @beta Efl.Ui.Textpath extends Efl.Ui.Layout_Base implements Efl.Text, Efl. { [[Efl Ui Textpath class]] methods { - circle_set { - [[Set a circle with given center, radius, and start angle.]] + circular_set { + [[Set a circle with given radius and start angle. + The center of the circle will be decided by the object center position.]] params { - @in x: double; [[X coordinate of center]] - @in y: double; [[Y coordinate of center]] @in radius: double; [[Radius of the circle]] @in start_angle: double; [[Start angle of the circle]] @in direction: Efl.Ui.Textpath_Direction; [[Textpath direction]] diff --git a/src/lib/elementary/efl_ui_textpath_eo.legacy.c b/src/lib/elementary/efl_ui_textpath_eo.legacy.c index e810a856dd..1af5fdb1f8 100644 --- a/src/lib/elementary/efl_ui_textpath_eo.legacy.c +++ b/src/lib/elementary/efl_ui_textpath_eo.legacy.c @@ -1,8 +1,8 @@ EAPI void -elm_textpath_circle_set(Efl_Ui_Textpath *obj, double x, double y, double radius, double start_angle, Efl_Ui_Textpath_Direction direction) +elm_textpath_circular_set(Efl_Ui_Textpath *obj, double radius, double start_angle, Efl_Ui_Textpath_Direction direction) { - efl_ui_textpath_circle_set(obj, x, y, radius, start_angle, direction); + efl_ui_textpath_circular_set(obj, radius, start_angle, direction); } EAPI void @@ -23,6 +23,7 @@ elm_textpath_ellipsis_set(Efl_Ui_Textpath *obj, Eina_Bool ellipsis) efl_ui_textpath_ellipsis_set(obj, ellipsis); } + EAPI Eina_Bool elm_textpath_ellipsis_get(const Efl_Ui_Textpath *obj) { diff --git a/src/lib/elementary/efl_ui_textpath_eo.legacy.h b/src/lib/elementary/efl_ui_textpath_eo.legacy.h index 5fe981a2d8..65e8768c12 100644 --- a/src/lib/elementary/efl_ui_textpath_eo.legacy.h +++ b/src/lib/elementary/efl_ui_textpath_eo.legacy.h @@ -36,10 +36,26 @@ typedef enum * @param[in] start_angle Start angle of the circle * @param[in] direction Textpath direction * + * @see elm_textpath_circluar_set() + * * @ingroup Elm_Textpath_Group */ EAPI void elm_textpath_circle_set(Efl_Ui_Textpath *obj, double x, double y, double radius, double start_angle, Efl_Ui_Textpath_Direction direction); +/** + * @brief Set a circle with given radius, and start angle. + * The circle center will be decided by the object center position. + * + * @param[in] obj The object. + * @param[in] radius Radius of the circle + * @param[in] start_angle Start angle of the circle + * @param[in] direction Textpath direction + * + * @since 1.23 + * @ingroup Elm_Textpath_Group + */ +EAPI void elm_textpath_circular_set(Efl_Ui_Textpath *obj, double radius, double start_angle, Efl_Ui_Textpath_Direction direction); + /** * @brief The number of slices. The larger the number of slice_num is, The * better the text follows the path.