forked from enlightenment/efl
Evas textblock: improve and fix line range rectangles
The line range rectangles geometries needed a bit of adjusting. I started out with fixing T2648. In order to fill the gap between the end of the line and the margins, the geometry of the last line's character was used. I am not really sure why. Anyway, we have the line geometry, so I replaced it with that. Then, it led me to do some alignment checks, and indeed alignment cases were not treated. For instance, an LTR paragraph could have a line aligned with a value greater than 0.0. That means that we should fill the gap from the left of the line, if it was the last line in a multi-line selection. The inverse case is for RTL. I think it now works as it should. Will see if the selection logic is missing some more stuff once I come up with more example cases. Fixes T2648. @fix
This commit is contained in:
parent
326d0e548d
commit
7e8e392db6
|
@ -11212,6 +11212,39 @@ _evas_textblock_cursor_range_in_line_geometry_get(
|
|||
return rects;
|
||||
}
|
||||
|
||||
/* Helper that creates a selection rectangle to a given line.
|
||||
* The given 'inv' indicates an inverse behavior. */
|
||||
static Evas_Textblock_Rectangle *
|
||||
_line_fill_rect_get(const Evas_Object_Textblock_Line *ln,
|
||||
Evas_Coord w, Evas_Coord lm, Evas_Coord rm, Eina_Bool inv)
|
||||
{
|
||||
Evas_Textblock_Rectangle *tr;
|
||||
|
||||
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
||||
tr->y = ln->par->y + ln->y;
|
||||
tr->h = ln->h;
|
||||
|
||||
//Reminder: ln->x includes the left margin */
|
||||
if ((!inv && (ln->par->direction == EVAS_BIDI_DIRECTION_RTL)) ||
|
||||
(inv && (ln->par->direction != EVAS_BIDI_DIRECTION_RTL)))
|
||||
{
|
||||
tr->x = lm;
|
||||
tr->w = ln->x - lm;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr->x = ln->x + ln->w;
|
||||
tr->w = w - rm - tr->x;
|
||||
}
|
||||
|
||||
if (tr->w == 0)
|
||||
{
|
||||
free(tr);
|
||||
tr = NULL;
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
|
||||
EAPI Eina_Iterator *
|
||||
evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
|
||||
{
|
||||
|
@ -11254,9 +11287,12 @@ evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur
|
|||
int lm = 0, rm = 0;
|
||||
Eina_List *rects2 = NULL;
|
||||
Evas_Coord w;
|
||||
Evas_Textblock_Cursor *tc;
|
||||
Evas_Textblock_Rectangle *tr;
|
||||
|
||||
evas_object_geometry_get(cur1->obj, NULL, NULL, &w, NULL);
|
||||
|
||||
/* Use the minimum left margin and right margin for a uniform
|
||||
* line coverage of the rectangles */
|
||||
if (ln1->items)
|
||||
{
|
||||
Evas_Object_Textblock_Format *fm = ln1->items->format;
|
||||
|
@ -11267,30 +11303,29 @@ evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur
|
|||
}
|
||||
}
|
||||
|
||||
evas_object_geometry_get(cur1->obj, NULL, NULL, &w, NULL);
|
||||
if (ln2->items)
|
||||
{
|
||||
Evas_Object_Textblock_Format *fm = ln2->items->format;
|
||||
if (fm)
|
||||
{
|
||||
if (fm->margin.l < lm) lm = fm->margin.l;
|
||||
if (fm->margin.r < rm) rm = fm->margin.r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append the rectangles by visual order (top, middle, bottom). Keep
|
||||
* it like that so it is also easier to test and debug. */
|
||||
|
||||
/* Top line */
|
||||
rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1, cur1, NULL);
|
||||
|
||||
/* Extend selection rectangle in first line */
|
||||
tc = evas_object_textblock_cursor_new(cur1->obj);
|
||||
evas_textblock_cursor_copy(cur1, tc);
|
||||
evas_textblock_cursor_line_char_last(tc);
|
||||
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
||||
evas_textblock_cursor_pen_geometry_get(tc, &tr->x, &tr->y, &tr->w, &tr->h);
|
||||
if (ln1->par->direction == EVAS_BIDI_DIRECTION_RTL)
|
||||
/* Fill-in the top line */
|
||||
tr = _line_fill_rect_get(ln1, w, lm, rm, EINA_FALSE);
|
||||
if (tr)
|
||||
{
|
||||
tr->w = tr->x + tr->w - rm;
|
||||
tr->x = lm;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr->w = w - tr->x - rm;
|
||||
}
|
||||
rects = eina_list_append(rects, tr);
|
||||
evas_textblock_cursor_free(tc);
|
||||
}
|
||||
|
||||
rects2 = _evas_textblock_cursor_range_in_line_geometry_get(ln2, NULL, cur2);
|
||||
|
||||
/* Add middle rect */
|
||||
/* Middle rect (lines) */
|
||||
if ((ln1->par->y + ln1->y + ln1->h) != (ln2->par->y + ln2->y))
|
||||
{
|
||||
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
||||
|
@ -11300,6 +11335,15 @@ evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur
|
|||
tr->h = ln2->par->y + ln2->y - tr->y;
|
||||
rects = eina_list_append(rects, tr);
|
||||
}
|
||||
|
||||
/* Bottom line */
|
||||
rects2 = _evas_textblock_cursor_range_in_line_geometry_get(ln2, NULL, cur2);
|
||||
/* Fill-in the bottom line */
|
||||
tr = _line_fill_rect_get(ln2, w, lm, rm, EINA_TRUE);
|
||||
if (tr)
|
||||
{
|
||||
rects2 = eina_list_append(rects2, tr);
|
||||
}
|
||||
rects = eina_list_merge(rects, rects2);
|
||||
}
|
||||
itr = _evas_textblock_selection_iterator_new(rects);
|
||||
|
|
|
@ -2560,6 +2560,175 @@ START_TEST(evas_textblock_geometries)
|
|||
eina_iterator_free(it);
|
||||
eina_iterator_free(it2);
|
||||
|
||||
/* Check number of rectangles in case a of line wrapping */
|
||||
evas_object_textblock_text_markup_set(tb, "<wrap=word>abc def <color=#0ff>ghi");
|
||||
evas_object_resize(tb, w, w / 2);
|
||||
evas_textblock_cursor_pos_set(cur, 10);
|
||||
|
||||
{
|
||||
Evas_Coord cx;
|
||||
evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
EVAS_TEXTBLOCK_CURSOR_BEFORE);
|
||||
/* enforce wrapping of "ghi" to the next line */
|
||||
evas_object_resize(tb, cx, 400);
|
||||
/* Sanity, check there is actually a second line */
|
||||
fail_if (!evas_textblock_cursor_line_set(cur, 1));
|
||||
fail_if (evas_textblock_cursor_line_set(cur, 2));
|
||||
}
|
||||
|
||||
evas_textblock_cursor_pos_set(cur, 7);
|
||||
evas_textblock_cursor_pos_set(main_cur, 9);
|
||||
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
|
||||
{
|
||||
Evas_Coord y1, y2;
|
||||
void *tmp = tr;
|
||||
/* We have 3 rectangles */
|
||||
Eina_Iterator *itr = it;
|
||||
fail_if (!eina_iterator_next(itr, &tmp));
|
||||
tr = tmp;
|
||||
y1 = tr->y;
|
||||
fail_if (!eina_iterator_next(itr, &tmp));
|
||||
tr = tmp;
|
||||
y2 = tr->y;
|
||||
|
||||
/* Basically it means that the "extending" rectangle should not somehow
|
||||
* reach the second line in this example. */
|
||||
ck_assert_int_eq(y1, y2);
|
||||
eina_iterator_free(it);
|
||||
}
|
||||
|
||||
/* Alignment fills */
|
||||
|
||||
/* LTR text */
|
||||
evas_object_resize(tb, 400, 400);
|
||||
evas_object_textblock_text_markup_set(tb,
|
||||
"<align=0.1>"
|
||||
"Hello World<ps>"
|
||||
"How are you<ps>");
|
||||
evas_textblock_cursor_line_set(cur, 0);
|
||||
evas_textblock_cursor_line_set(main_cur, 1);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 4);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_line_set(main_cur, 2);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 4);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
eina_iterator_free(it);
|
||||
|
||||
/* RTL text aligned to the left */
|
||||
evas_object_textblock_text_markup_set(tb,
|
||||
"<align=left>"
|
||||
"שלום עולם<ps>"
|
||||
"מה שלומך");
|
||||
evas_textblock_cursor_line_set(cur, 0);
|
||||
evas_textblock_cursor_line_set(main_cur, 1);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 2);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
eina_iterator_free(it);
|
||||
|
||||
/* RTL text aligned to the middle */
|
||||
evas_object_textblock_text_markup_set(tb,
|
||||
"<align=middle>"
|
||||
"שלום עולם<ps>"
|
||||
"מה שלומך");
|
||||
evas_textblock_cursor_line_set(cur, 0);
|
||||
evas_textblock_cursor_line_set(main_cur, 1);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 4);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_object_textblock_text_markup_set(tb,
|
||||
"<align=middle>"
|
||||
"שלום עולם<ps>"
|
||||
"מה שלומך");
|
||||
evas_textblock_cursor_line_set(cur, 0);
|
||||
evas_textblock_cursor_line_set(main_cur, 1);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 4);
|
||||
eina_iterator_free(it);
|
||||
|
||||
/* Auto align RTL and LTR */
|
||||
evas_object_textblock_text_markup_set(tb,
|
||||
"Hello world<ps>"
|
||||
"מה שלומך");
|
||||
evas_textblock_cursor_line_set(cur, 0);
|
||||
evas_textblock_cursor_line_set(main_cur, 1);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 2);
|
||||
eina_iterator_free(it);
|
||||
|
||||
evas_textblock_cursor_char_next(main_cur);
|
||||
it = evas_textblock_cursor_range_simple_geometry_get(cur, main_cur);
|
||||
fail_if(!it);
|
||||
rects = eina_iterator_container_get(it);
|
||||
fail_if(!rects);
|
||||
ck_assert_int_eq(eina_list_count(rects), 3);
|
||||
eina_iterator_free(it);
|
||||
|
||||
/* Same run different scripts */
|
||||
evas_object_textblock_text_markup_set(tb, "עבריתenglishрусскийעברית");
|
||||
|
||||
|
|
Loading…
Reference in New Issue