summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hirt <daniel.hirt@samsung.com>2016-05-24 16:11:03 +0300
committerTom Hacohen <tom@stosb.com>2016-06-16 19:15:20 +0100
commit3a6c648d2805fbe76eeb93c0597c4180bd8b6e6d (patch)
treeb2a6a31b3a39fc2594ab37e25459d342df04a814
parent3adf6fdbae67ecdcc24b9c247ee2e41e42acfc09 (diff)
downloadefl-3a6c648d2805fbe76eeb93c0597c4180bd8b6e6d.tar.gz
Canvas text: introduce new text object
The implementation depends on creating different code paths from the now-legacy behavior of text appending. The annotation system introduced in this commit replaces the current way of applying formats on text. Up until now it has been quite a hassle for the user to control the formats, as it required keeping track of the format positions with an opener and closer formats almost every time (with the exception of own-closing formats). The combination of Efl.Text API along with the Efl.Canvas.Text annotation API essentially replaces the capabilities of the old format. There is additional annotation API to allow more control, so be sure to check the documentation/.eo files and the wiki page of Efl.Canvas.Text. The style API now accepts actual strings of format style. There is not longer need to instantiate as style with style_new() followed later by style_free(). @feature
-rw-r--r--src/Makefile_Evas.am3
-rw-r--r--src/lib/edje/edje_calc.c16
-rw-r--r--src/lib/evas/Evas_Common.h772
-rw-r--r--src/lib/evas/Evas_Eo.h4
-rw-r--r--src/lib/evas/Evas_Legacy.h57
-rw-r--r--src/lib/evas/Evas_Textblock_Legacy.h945
-rw-r--r--src/lib/evas/canvas/efl_canvas_text.eo451
-rw-r--r--src/lib/evas/canvas/evas_object_textblock.c1284
-rw-r--r--src/lib/evas/canvas/evas_textblock.eo331
-rw-r--r--src/lib/evas/canvas/evas_textblock_hyphenation.x4
-rw-r--r--src/tests/evas/evas_test_textblock.c399
11 files changed, 2815 insertions, 1451 deletions
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 344cdd2839..ec94ac9b03 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -5,7 +5,7 @@ evas_eolian_pub_files = \
lib/evas/canvas/evas_object.eo \
lib/evas/canvas/efl_canvas_polygon.eo \
lib/evas/canvas/efl_canvas_rectangle.eo \
- lib/evas/canvas/evas_textblock.eo \
+ lib/evas/canvas/efl_canvas_text.eo \
lib/evas/canvas/evas_object_smart.eo \
lib/evas/canvas/evas_common_interface.eo \
lib/evas/canvas/evas_canvas.eo \
@@ -100,6 +100,7 @@ lib/evas/Evas.h \
lib/evas/Evas_Common.h \
lib/evas/Evas_Eo.h \
lib/evas/Evas_Legacy.h \
+lib/evas/Evas_Textblock_Legacy.h \
lib/evas/Evas_GL.h \
lib/evas/Evas_Loader.h
diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c
index 6c474de79c..ad1d3c27ea 100644
--- a/src/lib/edje/edje_calc.c
+++ b/src/lib/edje/edje_calc.c
@@ -1495,7 +1495,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
if (ep->part->scale) base_s = TO_DOUBLE(sc);
evas_obj_scale_set(ep->object, base_s);
- evas_obj_textblock_size_native_get(ep->object, &tw, &th);
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
orig_s = base_s;
/* Now make it bigger so calculations will be more accurate
@@ -1504,7 +1504,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
orig_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
orig_s * TO_INT(params->eval.w) / tw);
evas_obj_scale_set(ep->object, orig_s);
- evas_obj_textblock_size_native_get(ep->object, &tw, &th);
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
}
if (chosen_desc->text.fit_x)
{
@@ -1513,7 +1513,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
orig_s * TO_INT(params->eval.w) / tw);
evas_obj_scale_set(ep->object, s);
- evas_obj_textblock_size_native_get(ep->object, NULL, NULL);
+ efl_canvas_text_size_native_get(ep->object, NULL, NULL);
}
}
if (chosen_desc->text.fit_y)
@@ -1530,7 +1530,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
}
evas_obj_scale_set(ep->object, s);
- evas_obj_textblock_size_native_get(ep->object, NULL, NULL);
+ efl_canvas_text_size_native_get(ep->object, NULL, NULL);
}
}
@@ -1539,7 +1539,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
{
int i = 5; /* Tries before we give up. */
Evas_Coord fw, fh;
- evas_obj_textblock_size_native_get(ep->object, &fw, &fh);
+ efl_canvas_text_size_native_get(ep->object, &fw, &fh);
/* If we are still too big, try reducing the size to
* 95% each try. */
@@ -1555,7 +1555,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
s = tmp_s;
evas_obj_scale_set(ep->object, s);
- evas_obj_textblock_size_native_get(ep->object, &fw, &fh);
+ efl_canvas_text_size_native_get(ep->object, &fw, &fh);
i--;
}
}
@@ -1582,7 +1582,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
if (!chosen_desc->text.min_x)
{
efl_gfx_size_set(ep->object, TO_INT(params->eval.w), TO_INT(params->eval.h));
- evas_obj_textblock_size_formatted_get(ep->object, &tw, &th);
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
}
else
evas_object_textblock_size_native_get(ep->object, &tw, &th);
@@ -1609,7 +1609,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
if (!chosen_desc->text.max_x)
{
efl_gfx_size_set(ep->object, TO_INT(params->eval.w), TO_INT(params->eval.h));
- evas_obj_textblock_size_formatted_get(ep->object, &tw, &th);
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
}
else
evas_object_textblock_size_native_get(ep->object, &tw, &th);
diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h
index 725d12e35d..1dc0e108e6 100644
--- a/src/lib/evas/Evas_Common.h
+++ b/src/lib/evas/Evas_Common.h
@@ -2938,778 +2938,6 @@ EAPI Eina_Bool evas_object_image_extension_can_load_fast_get
*/
/**
- * @defgroup Evas_Object_Textblock Textblock Object Functions
- *
- * Functions used to create and manipulate textblock objects. Unlike
- * @ref Evas_Object_Text, these handle complex text, doing multiple
- * styles and multiline text based on HTML-like tags. Of these extra
- * features will be heavier on memory and processing cost.
- *
- * @section Evas_Object_Textblock_Tutorial Textblock Object Tutorial
- *
- * This part explains about the textblock object's API and proper usage.
- * The main user of the textblock object is the edje entry object in Edje, so
- * that's a good place to learn from, but I think this document is more than
- * enough, if it's not, please contact me and I'll update it.
- *
- * @subsection textblock_intro Introduction
- * The textblock objects is, as implied, an object that can show big chunks of
- * text. Textblock supports many features including: Text formatting, automatic
- * and manual text alignment, embedding items (for example icons) and more.
- * Textblock has three important parts, the text paragraphs, the format nodes
- * and the cursors.
- *
- * You can use markup to format text, for example: "<font_size=50>Big!</font_size>".
- * You can also put more than one style directive in one tag:
- * "<font_size=50 color=#F00>Big and Red!</font_size>".
- * Please notice that we used "</font_size>" although the format also included
- * color, this is because the first format determines the matching closing tag's
- * name. You can also use anonymous tags, like: "<font_size=30>Big</>" which
- * just pop any type of format, but it's advised to use the named alternatives
- * instead.
- *
- * @subsection textblock_cursors Textblock Object Cursors
- * A textblock Cursor is data type that represents
- * a position in a textblock. Each cursor contains information about the
- * paragraph it points to, the position in that paragraph and the object itself.
- * Cursors register to textblock objects upon creation, this means that once
- * you created a cursor, it belongs to a specific obj and you can't for example
- * copy a cursor "into" a cursor of a different object. Registered cursors
- * also have the added benefit of updating automatically upon textblock changes,
- * this means that if you have a cursor pointing to a specific character, it'll
- * still point to it even after you change the whole object completely (as long
- * as the char was not deleted), this is not possible without updating, because
- * as mentioned, each cursor holds a character position. There are many
- * functions that handle cursors, just check out the evas_textblock_cursor*
- * functions. For creation and deletion of cursors check out:
- * @see evas_object_textblock_cursor_new()
- * @see evas_textblock_cursor_free()
- * @note Cursors are generally the correct way to handle text in the textblock object, and there are enough functions to do everything you need with them (no need to get big chunks of text and processing them yourself).
- *
- * @subsection textblock_paragraphs Textblock Object Paragraphs
- * The textblock object is made out of text splitted to paragraphs (delimited
- * by the paragraph separation character). Each paragraph has many (or none)
- * format nodes associated with it which are responsible for the formatting
- * of that paragraph.
- *
- * @subsection textblock_format_nodes Textblock Object Format Nodes
- * As explained in @ref textblock_paragraphs each one of the format nodes
- * is associated with a paragraph.
- * There are two types of format nodes, visible and invisible:
- * Visible: formats that a cursor can point to, i.e formats that
- * occupy space, for example: newlines, tabs, items and etc. Some visible items
- * are made of two parts, in this case, only the opening tag is visible.
- * A closing tag (i.e a \</tag\> tag) should NEVER be visible.
- * Invisible: formats that don't occupy space, for example: bold and underline.
- * Being able to access format nodes is very important for some uses. For
- * example, edje uses the "<a>" format to create links in the text (and pop
- * popups above them when clicked). For the textblock object a is just a
- * formatting instruction (how to color the text), but edje utilizes the access
- * to the format nodes to make it do more.
- * For more information, take a look at all the evas_textblock_node_format_*
- * functions.
- * The translation of "<tag>" tags to actual format is done according to the
- * tags defined in the style, see @ref evas_textblock_style_set
- *
- * @subsection textblock_special_formats Special Formats
- * Textblock supports various format directives that can be used in markup. In
- * addition to the mentioned format directives, textblock allows creating
- * additional format directives using "tags" that can be set in the style see
- * @ref evas_textblock_style_set .
- *
- * For more details see @ref evas_textblock_style_page
- *
- * Textblock supports the following formats:
- * @li font - Font description in fontconfig like format, e.g: "Sans:style=Italic:lang=hi". or "Serif:style=Bold".
- * @li font_weight - Overrides the weight defined in "font". E.g: "font_weight=Bold" is the same as "font=:style=Bold". Supported weights: "normal", "thin", "ultralight", "light", "book", "medium", "semibold", "bold", "ultrabold", "black", and "extrablack".
- * @li font_style - Overrides the style defined in "font". E.g: "font_style=Italic" is the same as "font=:style=Italic". Supported styles: "normal", "oblique", and "italic".
- * @li font_width - Overrides the width defined in "font". E.g: "font_width=Condensed" is the same as "font=:style=Condensed". Supported widths: "normal", "ultracondensed", "extracondensed", "condensed", "semicondensed", "semiexpanded", "expanded", "extraexpanded", and "ultraexpanded".
- * @li lang - Overrides the language defined in "font". E.g: "lang=he" is the same as "font=:lang=he".
- * @li font_fallbacks - A comma delimited list of fonts to try if finding the main font fails.
- * @li font_size - The font size in points.
- * @li font_source - The source of the font, e.g an eet file.
- * @li color - Text color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li underline_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li underline2_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li outline_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li shadow_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li glow_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li glow2_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li strikethrough_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li align - Either "auto" (meaning according to text direction), "left", "right", "center", "middle", a value between 0.0 and 1.0, or a value between 0% to 100%.
- * @li valign - Either "top", "bottom", "middle", "center", "baseline", "base", a value between 0.0 and 1.0, or a value between 0% to 100%.
- * @li wrap - "word", "char", "mixed", or "none".
- * @li left_margin - Either "reset", or a pixel value indicating the margin.
- * @li right_margin - Either "reset", or a pixel value indicating the margin.
- * @li underline - "on", "off", "single", or "double".
- * @li strikethrough - "on" or "off"
- * @li backing_color - Background color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
- * @li backing - Enable/disable background color. ex) "on" or "off"
- * @li style - Either "off", "none", "plain", "shadow", "outline", "soft_outline", "outline_shadow", "outline_soft_shadow", "glow", "far_shadow", "soft_shadow", or "far_soft_shadow". Direction can be selected by adding "bottom_right", "bottom", "bottom_left", "left", "top_left", "top", "top_right", or "right". E.g: "style=shadow,bottom_right".
- * @li tabstops - Pixel value for tab width.
- * @li linesize - Force a line size in pixels.
- * @li linerelsize - Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
- * @li linegap - Force a line gap in pixels.
- * @li linerelgap - Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
- * @li item - Creates an empty space that should be filled by an upper layer. Use "size", "abssize", or "relsize". To define the items size, and an optional: vsize=full/ascent to define the item's position in the line.
- * @li linefill - Either a float value or percentage indicating how much to fill the line.
- * @li ellipsis - Value between 0.0-1.0 to indicate the type of ellipsis, or -1.0 to indicate ellipsis isn't wanted.
- * @li password - "on" or "off". This is used to specifically turn replacing chars with the replacement char (i.e password mode) on and off.
- *
- * @warning We don't guarantee any proper results if you create a Textblock
- * object
- * without setting the evas engine.
- *
- * @todo put here some usage examples
- *
- * @ingroup Evas_Object_Specific
- *
- * @{
- */
-
-/**
- * @typedef Evas_Textblock_Style
- *
- * A textblock style object.
- * @see evas_textblock_style_new()
- * @see evas_textblock_style_get()
- * @see evas_textblock_style_set()
- */
-
-typedef struct _Evas_Textblock_Style Evas_Textblock_Style;
-
-/**
- * @typedef Evas_Textblock_Cursor
- *
- * A textblock cursor object, used to maipulate the cursor of an evas textblock
- * @see evas_object_textblock_cursor_new
- *
- */
-typedef struct _Evas_Textblock_Cursor Evas_Textblock_Cursor;
-
-/**
- * @typedef Evas_Object_Textblock_Node_Format
- * A format node.
- *
- * XXX: Adapter for legacy.
- */
-typedef struct _Evas_Textblock_Node_Format Evas_Object_Textblock_Node_Format;
-
-typedef struct _Evas_Textblock_Rectangle Evas_Textblock_Rectangle;
-struct _Evas_Textblock_Rectangle
-{
- Evas_Coord x, y, w, h;
-};
-
-/**
- * Text type for evas textblock.
- */
-typedef enum _Evas_Textblock_Text_Type
-{
- EVAS_TEXTBLOCK_TEXT_RAW, /**< textblock text of type raw */
- EVAS_TEXTBLOCK_TEXT_PLAIN, /**< textblock text of type plain */
- EVAS_TEXTBLOCK_TEXT_MARKUP /**< textblock text of type markup */
-} Evas_Textblock_Text_Type;
-
-/**
- * Cursor type for evas textblock.
- */
-typedef enum _Evas_Textblock_Cursor_Type
-{
- EVAS_TEXTBLOCK_CURSOR_UNDER, /**< cursor type is under */
- EVAS_TEXTBLOCK_CURSOR_BEFORE /**< cursor type is before */
-} Evas_Textblock_Cursor_Type;
-
-/**
- * Returns the unescaped version of escape.
- * @param escape the string to be escaped
- * @return the unescaped version of escape
- */
-EAPI const char *evas_textblock_escape_string_get(const char *escape) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Returns the escaped version of the string.
- * @param string to escape
- * @param len_ret the len of the part of the string that was used.
- * @return the escaped string.
- */
-EAPI const char *evas_textblock_string_escape_get(const char *string, int *len_ret) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Return the unescaped version of the string between start and end.
- *
- * @param escape_start the start of the string.
- * @param escape_end the end of the string.
- * @return the unescaped version of the range
- */
-EAPI const char *evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Creates a new textblock style.
- * @return The new textblock style.
- */
-EAPI Evas_Textblock_Style *evas_textblock_style_new(void) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
-
-/**
- * Destroys a textblock style.
- * @param ts The textblock style to free.
- */
-EAPI void evas_textblock_style_free(Evas_Textblock_Style *ts) EINA_ARG_NONNULL(1);
-
-/**
- * Sets the style ts to the style passed as text by text.
- * Expected a string consisting of many (or none) tag='format' pairs.
- *
- * @param ts the style to set.
- * @param text the text to parse - NOT NULL.
- * @return Returns no value.
- */
-EAPI void evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) EINA_ARG_NONNULL(1);
-
-/**
- * Return the text of the style ts.
- * @param ts the style to get it's text.
- * @return the text of the style or null on error.
- */
-EAPI const char *evas_textblock_style_get(const Evas_Textblock_Style *ts) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Prepends markup to the cursor cur.
- *
- * @note assumes text does not include the unicode object replacement char (0xFFFC)
- *
- * @param cur the cursor to prepend to.
- * @param text the markup text to prepend.
- * @return Return no value.
- */
-EAPI void evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Free the cursor and unassociate it from the object.
- * @note do not use it to free unassociated cursors.
- *
- * @param cur the cursor to free.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_free(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Sets the cursor to the start of the first text node.
- *
- * @param cur the cursor to update.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * sets the cursor to the end of the last text node.
- *
- * @param cur the cursor to set.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Advances to the start of the next text node
- *
- * @param cur the cursor to update
- * @return @c EINA_TRUE if it managed to advance a paragraph, @c EINA_FALSE
- * otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Advances to the end of the previous text node
- *
- * @param cur the cursor to update
- * @return @c EINA_TRUE if it managed to advance a paragraph, @c EINA_FALSE
- * otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Returns the next format node (after n)
- *
- * @param n the current format node - not null.
- * @return Returns the next format node, may be null.
- */
-EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1);
-
-/**
- * Returns the prev format node (after n)
- *
- * @param n the current format node - not null.
- * @return Returns the prev format node, may be null.
- */
-EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1);
-
-/**
- * Sets the cursor to point to the place where format points to.
- *
- * @param cur the cursor to update.
- * @param n the format node to update according.
- * @deprecated duplicate of evas_textblock_cursor_at_format_set
- */
-EAPI void evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Return the format node at the position pointed by cur.
- *
- * @param cur the position to look at.
- * @return the format node if found, @c NULL otherwise.
- * @see evas_textblock_cursor_format_is_visible_get()
- */
-EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Get the text format representation of the format node.
- *
- * @param fnode the format node.
- * @return the textual format of the format node.
- */
-EAPI const char *evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fnode) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Set the cursor to point to the position of fmt.
- *
- * @param cur the cursor to update
- * @param fmt the format to update according to.
- */
-EAPI void evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Check if the current cursor position is a visible format. This way is more
- * efficient than evas_textblock_cursor_format_get() to check for the existence
- * of a visible format.
- *
- * @param cur the cursor to look at.
- * @return @c EINA_TRUE if the cursor points to a visible format, @c EINA_FALSE
- * otherwise.
- * @see evas_textblock_cursor_format_get()
- */
-EAPI Eina_Bool evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Advances to the next format node
- *
- * @param cur the cursor to be updated.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Advances to the previous format node.
- *
- * @param cur the cursor to update.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Returns true if the cursor points to a format.
- *
- * @param cur the cursor to check.
- * @return @c EINA_TRUE if a cursor points to a format @c EINA_FALSE
- * otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Advances 1 char forward.
- *
- * @param cur the cursor to advance.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Advances 1 char backward.
- *
- * @param cur the cursor to advance.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Moves the cursor to the start of the word under the cursor.
- *
- * @param cur the cursor to move.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- * @since 1.2
- */
-EAPI Eina_Bool evas_textblock_cursor_word_start(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Moves the cursor to the end of the word under the cursor.
- *
- * @param cur the cursor to move.
- * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
- * @since 1.2
- */
-EAPI Eina_Bool evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Go to the first char in the node the cursor is pointing on.
- *
- * @param cur the cursor to update.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Go to the last char in a text node.
- *
- * @param cur the cursor to update.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Go to the start of the current line
- *
- * @param cur the cursor to update.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Go to the end of the current line.
- *
- * @param cur the cursor to update.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Return the current cursor pos.
- *
- * @param cur the cursor to take the position from.
- * @return the position or -1 on error
- */
-EAPI int evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Set the cursor pos.
- *
- * @param cur the cursor to be set.
- * @param pos the pos to set.
- */
-EAPI void evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int pos) EINA_ARG_NONNULL(1);
-
-/**
- * Go to the start of the line passed
- *
- * @param cur cursor to update.
- * @param line numer to set.
- * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
- */
-EAPI Eina_Bool evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line) EINA_ARG_NONNULL(1);
-
-/**
- * Compare two cursors.
- *
- * @param cur1 the first cursor.
- * @param cur2 the second cursor.
- * @return -1 if cur1 < cur2, 0 if cur1 == cur2 and 1 otherwise.
- */
-EAPI int evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Make cur_dest point to the same place as cur. Does not work if they don't
- * point to the same object.
- *
- * @param cur the source cursor.
- * @param cur_dest destination cursor.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Adds text to the current cursor position and set the cursor to *before*
- * the start of the text just added.
- *
- * @param cur the cursor to where to add text at.
- * @param text the text to add.
- * @return Returns the len of the text added.
- * @see evas_textblock_cursor_text_prepend()
- */
-EAPI int evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Adds text to the current cursor position and set the cursor to *after*
- * the start of the text just added.
- *
- * @param cur the cursor to where to add text at.
- * @param text the text to add.
- * @return Returns the len of the text added.
- * @see evas_textblock_cursor_text_append()
- */
-EAPI int evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Adds format to the current cursor position. If the format being added is a
- * visible format, add it *before* the cursor position, otherwise, add it after.
- * This behavior is because visible formats are like characters and invisible
- * should be stacked in a way that the last one is added last.
- *
- * This function works with native formats, that means that style defined
- * tags like <br> won't work here. For those kind of things use markup prepend.
- *
- * @param cur the cursor to where to add format at.
- * @param format the format to add.
- * @return Returns true if a visible format was added, false otherwise.
- * @see evas_textblock_cursor_format_prepend()
- */
-
-/**
- * Check if the current cursor position points to the terminating null of the
- * last paragraph. (shouldn't be allowed to point to the terminating null of
- * any previous paragraph anyway.
- *
- * @param cur the cursor to look at.
- * @return @c EINA_TRUE if the cursor points to the terminating null, @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Adds format to the current cursor position. If the format being added is a
- * visible format, add it *before* the cursor position, otherwise, add it after.
- * This behavior is because visible formats are like characters and invisible
- * should be stacked in a way that the last one is added last.
- * If the format is visible the cursor is advanced after it.
- *
- * This function works with native formats, that means that style defined
- * tags like <br> won't work here. For those kind of things use markup prepend.
- *
- * @param cur the cursor to where to add format at.
- * @param format the format to add.
- * @return Returns true if a visible format was added, false otherwise.
- * @see evas_textblock_cursor_format_prepend()
- */
-EAPI Eina_Bool evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Delete the character at the location of the cursor. If there's a format
- * pointing to this position, delete it as well.
- *
- * @param cur the cursor pointing to the current location.
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
-
-/**
- * Delete the range between cur1 and cur2.
- *
- * @param cur1 one side of the range.
- * @param cur2 the second side of the range
- * @return Returns no value.
- */
-EAPI void evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Return the text of the paragraph cur points to - returns the text in markup.
- *
- * @param cur the cursor pointing to the paragraph.
- * @return the text on success, @c NULL otherwise.
- */
-EAPI const char *evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Return the length of the paragraph, cheaper the eina_unicode_strlen()
- *
- * @param cur the position of the paragraph.
- * @return the length of the paragraph on success, -1 otehrwise.
- */
-EAPI int evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * Return the currently visible range.
- *
- * @param start the start of the range.
- * @param end the end of the range.
- * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
- * @since 1.1
- */
-EAPI Eina_Bool evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textblock_Cursor *end) EINA_ARG_NONNULL(1, 2);
-
-/**
- * Return the format nodes in the range between cur1 and cur2.
- *
- * @param cur1 one side of the range.
- * @param cur2 the other side of the range
- * @return the foramt nodes in the range. You have to free it.
- * @since 1.1
- */
-EAPI Eina_List *evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Return the text in the range between cur1 and cur2
- *
- * @param cur1 one side of the range.
- * @param cur2 the other side of the range
- * @param format The form on which to return the text. Markup - in textblock markup. Plain - UTF8.
- * @return the text in the range
- * @see elm_entry_markup_to_utf8()
- */
-EAPI char *evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Return the content of the cursor.
- *
- * Free the returned string pointer when done (if it is not NULL).
- *
- * @param cur the cursor
- * @return the text in the range, terminated by a nul byte (may be utf8).
- */
-EAPI char *evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
-
-/**
- * Returns the geometry of two cursors ("split cursor"), if logical cursor is
- * between LTR/RTL text, also considering paragraph direction.
- * Upper cursor is shown for the text of the same direction as paragraph,
- * lower cursor - for opposite.
- *
- * Split cursor geometry is valid only in '|' cursor mode.
- * In this case @c EINA_TRUE is returned and cx2, cy2, cw2, ch2 are set,
- * otherwise it behaves like cursor_geometry_get.
- *
- * @param[in] cur the cursor.
- * @param[out] cx the x of the cursor (or upper cursor)
- * @param[out] cy the y of the cursor (or upper cursor)
- * @param[out] cw the width of the cursor (or upper cursor)
- * @param[out] ch the height of the cursor (or upper cursor)
- * @param[out] cx2 the x of the lower cursor
- * @param[out] cy2 the y of the lower cursor
- * @param[out] cw2 the width of the lower cursor
- * @param[out] ch2 the height of the lower cursor
- * @param[in] ctype the type of the cursor.
- * @return @c EINA_TRUE for split cursor, @c EINA_FALSE otherwise
- * @since 1.8
- */
-EAPI Eina_Bool
-evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype);
-
-/**
- * Returns the geometry of the cursor. Depends on the type of cursor requested.
- * This should be used instead of char_geometry_get because there are weird
- * special cases with BiDi text.
- * in '_' cursor mode (i.e a line below the char) it's the same as char_geometry
- * get, except for the case of the last char of a line which depends on the
- * paragraph direction.
- *
- * in '|' cursor mode (i.e a line between two chars) it is very variable.
- * For example consider the following visual string:
- * "abcCBA" (ABC are rtl chars), a cursor pointing on A should actually draw
- * a '|' between the c and the C.
- *
- * @param cur the cursor.
- * @param cx the x of the cursor
- * @param cy the y of the cursor
- * @param cw the width of the cursor
- * @param ch the height of the cursor
- * @param dir the direction of the cursor, can be NULL.
- * @param ctype the type of the cursor.
- * @return line number of the char on success, -1 on error.
- */
-EAPI int evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype) EINA_ARG_NONNULL(1);
-
-/**
- * Returns the geometry of the char at cur.
- *
- * @param cur the position of the char.
- * @param cx the x of the char.
- * @param cy the y of the char.
- * @param cw the w of the char.
- * @param ch the h of the char.
- * @return line number of the char on success, -1 on error.
- */
-EAPI int evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
-
-/**
- * Returns the geometry of the pen at cur.
- *
- * @param cur the position of the char.
- * @param cpen_x the pen_x of the char.
- * @param cy the y of the char.
- * @param cadv the adv of the char.
- * @param ch the h of the char.
- * @return line number of the char on success, -1 on error.
- */
-EAPI int evas_textblock_cursor_pen_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cpen_x, Evas_Coord *cy, Evas_Coord *cadv, Evas_Coord *ch) EINA_ARG_NONNULL(1);
-
-/**
- * Returns the geometry of the line at cur.
- *
- * @param cur the position of the line.
- * @param cx the x of the line.
- * @param cy the y of the line.
- * @param cw the width of the line.
- * @param ch the height of the line.
- * @return line number of the line on success, -1 on error.
- */
-EAPI int evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
-
-/**
- * Set the position of the cursor according to the X and Y coordinates.
- *
- * @param cur the cursor to set.
- * @param x coord to set by.
- * @param y coord to set by.
- * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y) EINA_ARG_NONNULL(1);
-
-/**
- * Set the cursor position according to the y coord.
- *
- * @param cur the cur to be set.
- * @param y the coord to set by.
- * @return the line number found, -1 on error.
- */
-EAPI int evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y) EINA_ARG_NONNULL(1);
-
-/**
- * Get the geometry of a range.
- *
- * @param cur1 one side of the range.
- * @param cur2 other side of the range.
- * @return a list of Rectangles representing the geometry of the range.
- */
-EAPI Eina_List *evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Get the simple geometry of a range.
- * The simple geometry is the geomtry in which rectangles in middle
- * lines of range are merged into one big rectangle.
- * @since 1.13
- *
- * @param cur1 one side of the range.
- * @param cur2 other side of the range.
- * @return an iterator of rectangles representing the geometry of the range.
- */
-EAPI Eina_Iterator *evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
-
-/**
- * Get the geometry of ?
- *
- * @param cur one side of the range.
- * @param cur2 other side of the range.
- */
-EAPI Eina_Bool evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
-
-/**
- * Checks if the cursor points to the end of the line.
- *
- * @param cur the cursor to check.
- * @return @c EINA_TRUE if true, @c EINA_FALSE otherwise.
- */
-EAPI Eina_Bool evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
-
-/**
- * @}
- */
-
-/**
* @defgroup Evas_Object_Textgrid Textgrid Object Functions
*
* @todo put here some usage examples
diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h
index 2468db1c9d..1934d0865f 100644
--- a/src/lib/evas/Evas_Eo.h
+++ b/src/lib/evas/Evas_Eo.h
@@ -22,11 +22,11 @@
*/
/**
- * @ingroup Evas_Object_Textblock
+ * @ingroup Efl_Canvas_Text
*
* @{
*/
-#include "canvas/evas_textblock.eo.h"
+#include "canvas/efl_canvas_text.eo.h"
/**
* @}
*/
diff --git a/src/lib/evas/Evas_Legacy.h b/src/lib/evas/Evas_Legacy.h
index 173eaea8ac..9f982ad4d5 100644
--- a/src/lib/evas/Evas_Legacy.h
+++ b/src/lib/evas/Evas_Legacy.h
@@ -4496,62 +4496,7 @@ EAPI void evas_object_text_font_get(const Eo *obj, const char **font, Evas_Font_
* @}
*/
-/**
- * @ingroup Evas_Object_Textblock
- *
- * @{
- */
-
-/**
- * Adds a textblock to the given evas.
- * @param e The given evas.
- * @return The new textblock object.
- */
-EAPI Evas_Object *evas_object_textblock_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
-
-/**
- * Return the plain version of the markup.
- *
- * Works as if you set the markup to a textblock and then retrieve the plain
- * version of the text. i.e: <br> and <\n> will be replaced with \n, &...; with
- * the actual char and etc.
- *
- * @param obj The textblock object to work with. (if @c NULL, tries the
- * default).
- * @param text The markup text (if @c NULL, return @c NULL).
- * @return An allocated plain text version of the markup.
- * @since 1.2
- */
-EAPI char *evas_textblock_text_markup_to_utf8(const Evas_Object *obj, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
-
-/**
- * Return the markup version of the plain text.
- *
- * Replaces \\n -\> \<br/\> \\t -\> \<tab/\> and etc. Generally needed before you pass
- * plain text to be set in a textblock.
- *
- * @param obj the textblock object to work with (if @c NULL, it just does the
- * default behaviour, i.e with no extra object information).
- * @param text The plain text (if @c NULL, return @c NULL).
- * @return An allocated markup version of the plain text.
- * @since 1.2
- */
-EAPI char *evas_textblock_text_utf8_to_markup(const Evas_Object *obj, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
-
-/**
- * Clear the textblock object.
- * @note Does *NOT* free the Evas object itself.
- *
- * @param obj the object to clear.
- * @return nothing.
- */
-EAPI void evas_object_textblock_clear(Evas_Object *obj) EINA_ARG_NONNULL(1);
-
-#include "canvas/evas_textblock.eo.legacy.h"
-
-/**
- * @}
- */
+#include "Evas_Textblock_Legacy.h"
/**
* @ingroup Evas_Object_Grid
diff --git a/src/lib/evas/Evas_Textblock_Legacy.h b/src/lib/evas/Evas_Textblock_Legacy.h
new file mode 100644
index 0000000000..b9e00c2505
--- /dev/null
+++ b/src/lib/evas/Evas_Textblock_Legacy.h
@@ -0,0 +1,945 @@
+/**
+ * @defgroup Evas_Object_Textblock Textblock Object Functions
+ *
+ * Functions used to create and manipulate textblock objects. Unlike
+ * @ref Evas_Object_Text, these handle complex text, doing multiple
+ * styles and multiline text based on HTML-like tags. Of these extra
+ * features will be heavier on memory and processing cost.
+ *
+ * @section Evas_Object_Textblock_Tutorial Textblock Object Tutorial
+ *
+ * This part explains about the textblock object's API and proper usage.
+ * The main user of the textblock object is the edje entry object in Edje, so
+ * that's a good place to learn from, but I think this document is more than
+ * enough, if it's not, please contact me and I'll update it.
+ *
+ * @subsection textblock_intro Introduction
+ * The textblock objects is, as implied, an object that can show big chunks of
+ * text. Textblock supports many features including: Text formatting, automatic
+ * and manual text alignment, embedding items (for example icons) and more.
+ * Textblock has three important parts, the text paragraphs, the format nodes
+ * and the cursors.
+ *
+ * You can use markup to format text, for example: "<font_size=50>Big!</font_size>".
+ * You can also put more than one style directive in one tag:
+ * "<font_size=50 color=#F00>Big and Red!</font_size>".
+ * Please notice that we used "</font_size>" although the format also included
+ * color, this is because the first format determines the matching closing tag's
+ * name. You can also use anonymous tags, like: "<font_size=30>Big</>" which
+ * just pop any type of format, but it's advised to use the named alternatives
+ * instead.
+ *
+ * @subsection textblock_cursors Textblock Object Cursors
+ * A textblock Cursor is data type that represents
+ * a position in a textblock. Each cursor contains information about the
+ * paragraph it points to, the position in that paragraph and the object itself.
+ * Cursors register to textblock objects upon creation, this means that once
+ * you created a cursor, it belongs to a specific obj and you can't for example
+ * copy a cursor "into" a cursor of a different object. Registered cursors
+ * also have the added benefit of updating automatically upon textblock changes,
+ * this means that if you have a cursor pointing to a specific character, it'll
+ * still point to it even after you change the whole object completely (as long
+ * as the char was not deleted), this is not possible without updating, because
+ * as mentioned, each cursor holds a character position. There are many
+ * functions that handle cursors, just check out the evas_textblock_cursor*
+ * functions. For creation and deletion of cursors check out:
+ * @see evas_object_textblock_cursor_new()
+ * @see evas_textblock_cursor_free()
+ * @note Cursors are generally the correct way to handle text in the textblock object, and there are enough functions to do everything you need with them (no need to get big chunks of text and processing them yourself).
+ *
+ * @subsection textblock_paragraphs Textblock Object Paragraphs
+ * The textblock object is made out of text splitted to paragraphs (delimited
+ * by the paragraph separation character). Each paragraph has many (or none)
+ * format nodes associated with it which are responsible for the formatting
+ * of that paragraph.
+ *
+ * @subsection textblock_format_nodes Textblock Object Format Nodes
+ * As explained in @ref textblock_paragraphs each one of the format nodes
+ * is associated with a paragraph.
+ * There are two types of format nodes, visible and invisible:
+ * Visible: formats that a cursor can point to, i.e formats that
+ * occupy space, for example: newlines, tabs, items and etc. Some visible items
+ * are made of two parts, in this case, only the opening tag is visible.
+ * A closing tag (i.e a \</tag\> tag) should NEVER be visible.
+ * Invisible: formats that don't occupy space, for example: bold and underline.
+ * Being able to access format nodes is very important for some uses. For
+ * example, edje uses the "<a>" format to create links in the text (and pop
+ * popups above them when clicked). For the textblock object a is just a
+ * formatting instruction (how to color the text), but edje utilizes the access
+ * to the format nodes to make it do more.
+ * For more information, take a look at all the evas_textblock_node_format_*
+ * functions.
+ * The translation of "<tag>" tags to actual format is done according to the
+ * tags defined in the style, see @ref evas_textblock_style_set
+ *
+ * @subsection textblock_special_formats Special Formats
+ * Textblock supports various format directives that can be used in markup. In
+ * addition to the mentioned format directives, textblock allows creating
+ * additional format directives using "tags" that can be set in the style see
+ * @ref evas_textblock_style_set .
+ *
+ * For more details see @ref evas_textblock_style_page
+ *
+ * Textblock supports the following formats:
+ * @li font - Font description in fontconfig like format, e.g: "Sans:style=Italic:lang=hi". or "Serif:style=Bold".
+ * @li font_weight - Overrides the weight defined in "font". E.g: "font_weight=Bold" is the same as "font=:style=Bold". Supported weights: "normal", "thin", "ultralight", "light", "book", "medium", "semibold", "bold", "ultrabold", "black", and "extrablack".
+ * @li font_style - Overrides the style defined in "font". E.g: "font_style=Italic" is the same as "font=:style=Italic". Supported styles: "normal", "oblique", and "italic".
+ * @li font_width - Overrides the width defined in "font". E.g: "font_width=Condensed" is the same as "font=:style=Condensed". Supported widths: "normal", "ultracondensed", "extracondensed", "condensed", "semicondensed", "semiexpanded", "expanded", "extraexpanded", and "ultraexpanded".
+ * @li lang - Overrides the language defined in "font". E.g: "lang=he" is the same as "font=:lang=he".
+ * @li font_fallbacks - A comma delimited list of fonts to try if finding the main font fails.
+ * @li font_size - The font size in points.
+ * @li font_source - The source of the font, e.g an eet file.
+ * @li color - Text color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li underline_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li underline2_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li outline_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li shadow_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li glow_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li glow2_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li strikethrough_color - color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li align - Either "auto" (meaning according to text direction), "left", "right", "center", "middle", a value between 0.0 and 1.0, or a value between 0% to 100%.
+ * @li valign - Either "top", "bottom", "middle", "center", "baseline", "base", a value between 0.0 and 1.0, or a value between 0% to 100%.
+ * @li wrap - "word", "char", "mixed", or "none".
+ * @li left_margin - Either "reset", or a pixel value indicating the margin.
+ * @li right_margin - Either "reset", or a pixel value indicating the margin.
+ * @li underline - "on", "off", "single", or "double".
+ * @li strikethrough - "on" or "off"
+ * @li backing_color - Background color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", and "#RGBA".
+ * @li backing - Enable/disable background color. ex) "on" or "off"
+ * @li style - Either "off", "none", "plain", "shadow", "outline", "soft_outline", "outline_shadow", "outline_soft_shadow", "glow", "far_shadow", "soft_shadow", or "far_soft_shadow". Direction can be selected by adding "bottom_right", "bottom", "bottom_left", "left", "top_left", "top", "top_right", or "right". E.g: "style=shadow,bottom_right".
+ * @li tabstops - Pixel value for tab width.
+ * @li linesize - Force a line size in pixels.
+ * @li linerelsize - Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
+ * @li linegap - Force a line gap in pixels.
+ * @li linerelgap - Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
+ * @li item - Creates an empty space that should be filled by an upper layer. Use "size", "abssize", or "relsize". To define the items size, and an optional: vsize=full/ascent to define the item's position in the line.
+ * @li linefill - Either a float value or percentage indicating how much to fill the line.
+ * @li ellipsis - Value between 0.0-1.0 to indicate the type of ellipsis, or -1.0 to indicate ellipsis isn't wanted.
+ * @li password - "on" or "off". This is used to specifically turn replacing chars with the replacement char (i.e password mode) on and off.
+ *
+ * @warning We don't guarantee any proper results if you create a Textblock
+ * object
+ * without setting the evas engine.
+ *
+ * @todo put here some usage examples
+ *
+ * @ingroup Evas_Object_Specific
+ *
+ * @{
+ */
+
+/**
+ * @typedef Evas_Textblock_Style
+ *
+ * A textblock style object.
+ * @see evas_textblock_style_new()
+ * @see evas_textblock_style_get()
+ * @see evas_textblock_style_set()
+ */
+
+typedef struct _Efl_Canvas_Text_Style Evas_Textblock_Style;
+
+/**
+ * @typedef Evas_Textblock_Cursor
+ *
+ * A textblock cursor object, used to maipulate the cursor of an evas textblock
+ * @see evas_object_textblock_cursor_new
+ *
+ */
+typedef struct _Efl_Canvas_Text_Cursor Evas_Textblock_Cursor;
+
+/**
+ * @typedef Evas_Object_Textblock_Node_Format
+ * A format node.
+ *
+ * XXX: Adapter for legacy.
+ */
+typedef struct _Evas_Textblock_Node_Format Evas_Object_Textblock_Node_Format;
+
+/**
+ * @typedef Evas_Textblock_Rectangle
+ * General-purpose rectangle that represents some geometry in this object.
+ *
+ */
+typedef Eina_Rectangle Evas_Textblock_Rectangle;
+
+/**
+ * Text type for evas textblock.
+ */
+typedef enum _Evas_Textblock_Text_Type
+{
+ EVAS_TEXTBLOCK_TEXT_RAW, /**< textblock text of type raw */
+ EVAS_TEXTBLOCK_TEXT_PLAIN, /**< textblock text of type plain */
+ EVAS_TEXTBLOCK_TEXT_MARKUP /**< textblock text of type markup */
+} Evas_Textblock_Text_Type;
+
+/**
+ * Cursor type for evas textblock.
+ */
+typedef enum _Evas_Textblock_Cursor_Type
+{
+ EVAS_TEXTBLOCK_CURSOR_UNDER, /**< cursor type is under */
+ EVAS_TEXTBLOCK_CURSOR_BEFORE /**< cursor type is before */
+} Evas_Textblock_Cursor_Type;
+
+/**
+ * Returns the unescaped version of escape.
+ * @param escape the string to be escaped
+ * @return the unescaped version of escape
+ */
+EAPI const char *evas_textblock_escape_string_get(const char *escape) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the escaped version of the string.
+ * @param string to escape
+ * @param len_ret the len of the part of the string that was used.
+ * @return the escaped string.
+ */
+EAPI const char *evas_textblock_string_escape_get(const char *string, int *len_ret) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Return the unescaped version of the string between start and end.
+ *
+ * @param escape_start the start of the string.
+ * @param escape_end the end of the string.
+ * @return the unescaped version of the range
+ */
+EAPI const char *evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Creates a new textblock style.
+ * @return The new textblock style.
+ */
+EAPI Evas_Textblock_Style *evas_textblock_style_new(void) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
+
+/**
+ * Destroys a textblock style.
+ * @param ts The textblock style to free.
+ */
+EAPI void evas_textblock_style_free(Evas_Textblock_Style *ts) EINA_ARG_NONNULL(1);
+
+/**
+ * Sets the style ts to the style passed as text by text.
+ * Expected a string consisting of many (or none) tag='format' pairs.
+ *
+ * @param ts the style to set.
+ * @param text the text to parse - NOT NULL.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) EINA_ARG_NONNULL(1);
+
+/**
+ * Return the text of the style ts.
+ * @param ts the style to get it's text.
+ * @return the text of the style or null on error.
+ */
+EAPI const char *evas_textblock_style_get(const Evas_Textblock_Style *ts) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Free the cursor and unassociate it from the object.
+ * @note do not use it to free unassociated cursors.
+ *
+ * @param cur the cursor to free.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_free(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Sets the cursor to the start of the first text node.
+ *
+ * @param cur the cursor to update.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * sets the cursor to the end of the last text node.
+ *
+ * @param cur the cursor to set.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Advances to the start of the next text node
+ *
+ * @param cur the cursor to update
+ * @return @c EINA_TRUE if it managed to advance a paragraph, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Advances to the end of the previous text node
+ *
+ * @param cur the cursor to update
+ * @return @c EINA_TRUE if it managed to advance a paragraph, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the next format node (after n)
+ *
+ * @param n the current format node - not null.
+ * @return Returns the next format node, may be null.
+ */
+EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the prev format node (after n)
+ *
+ * @param n the current format node - not null.
+ * @return Returns the prev format node, may be null.
+ */
+EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1);
+
+/**
+ * Sets the cursor to point to the place where format points to.
+ *
+ * @param cur the cursor to update.
+ * @param n the format node to update according.
+ * @deprecated duplicate of evas_textblock_cursor_at_format_set
+ */
+EAPI void evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the format node at the position pointed by cur.
+ *
+ * @param cur the position to look at.
+ * @return the format node if found, @c NULL otherwise.
+ * @see evas_textblock_cursor_format_is_visible_get()
+ */
+EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Get the text format representation of the format node.
+ *
+ * @param fnode the format node.
+ * @return the textual format of the format node.
+ */
+EAPI const char *evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fnode) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Set the cursor to point to the position of fmt.
+ *
+ * @param cur the cursor to update
+ * @param fmt the format to update according to.
+ */
+EAPI void evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Check if the current cursor position is a visible format. This way is more
+ * efficient than evas_textblock_cursor_format_get() to check for the existence
+ * of a visible format.
+ *
+ * @param cur the cursor to look at.
+ * @return @c EINA_TRUE if the cursor points to a visible format, @c EINA_FALSE
+ * otherwise.
+ * @see evas_textblock_cursor_format_get()
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Advances to the next format node
+ *
+ * @param cur the cursor to be updated.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Advances to the previous format node.
+ *
+ * @param cur the cursor to update.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns true if the cursor points to a format.
+ *
+ * @param cur the cursor to check.
+ * @return @c EINA_TRUE if a cursor points to a format @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Advances 1 char forward.
+ *
+ * @param cur the cursor to advance.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Advances 1 char backward.
+ *
+ * @param cur the cursor to advance.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Moves the cursor to the start of the word under the cursor.
+ *
+ * @param cur the cursor to move.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ * @since 1.2
+ */
+EAPI Eina_Bool evas_textblock_cursor_word_start(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Moves the cursor to the end of the word under the cursor.
+ *
+ * @param cur the cursor to move.
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ * @since 1.2
+ */
+EAPI Eina_Bool evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Go to the first char in the node the cursor is pointing on.
+ *
+ * @param cur the cursor to update.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Go to the last char in a text node.
+ *
+ * @param cur the cursor to update.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Go to the start of the current line
+ *
+ * @param cur the cursor to update.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Go to the end of the current line.
+ *
+ * @param cur the cursor to update.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Return the current cursor pos.
+ *
+ * @param cur the cursor to take the position from.
+ * @return the position or -1 on error
+ */
+EAPI int evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Set the cursor pos.
+ *
+ * @param cur the cursor to be set.
+ * @param pos the pos to set.
+ */
+EAPI void evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int pos) EINA_ARG_NONNULL(1);
+
+/**
+ * Go to the start of the line passed
+ *
+ * @param cur cursor to update.
+ * @param line numer to set.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ */
+EAPI Eina_Bool evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line) EINA_ARG_NONNULL(1);
+
+/**
+ * Compare two cursors.
+ *
+ * @param cur1 the first cursor.
+ * @param cur2 the second cursor.
+ * @return -1 if cur1 < cur2, 0 if cur1 == cur2 and 1 otherwise.
+ */
+EAPI int evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Make cur_dest point to the same place as cur. Does not work if they don't
+ * point to the same object.
+ *
+ * @param cur the source cursor.
+ * @param cur_dest destination cursor.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Adds text to the current cursor position and set the cursor to *before*
+ * the start of the text just added.
+ *
+ * @param cur the cursor to where to add text at.
+ * @param text the text to add.
+ * @return Returns the len of the text added.
+ * @see evas_textblock_cursor_text_prepend()
+ */
+EAPI int evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Adds text to the current cursor position and set the cursor to *after*
+ * the start of the text just added.
+ *
+ * @param cur the cursor to where to add text at.
+ * @param text the text to add.
+ * @return Returns the len of the text added.
+ * @see evas_textblock_cursor_text_append()
+ */
+EAPI int evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Adds format to the current cursor position. If the format being added is a
+ * visible format, add it *before* the cursor position, otherwise, add it after.
+ * This behavior is because visible formats are like characters and invisible
+ * should be stacked in a way that the last one is added last.
+ *
+ * This function works with native formats, that means that style defined
+ * tags like <br> won't work here. For those kind of things use markup prepend.
+ *
+ * @param cur the cursor to where to add format at.
+ * @param format the format to add.
+ * @return Returns true if a visible format was added, false otherwise.
+ * @see evas_textblock_cursor_format_prepend()
+ */
+
+/**
+ * Check if the current cursor position points to the terminating null of the
+ * last paragraph. (shouldn't be allowed to point to the terminating null of
+ * any previous paragraph anyway.
+ *
+ * @param cur the cursor to look at.
+ * @return @c EINA_TRUE if the cursor points to the terminating null, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Adds format to the current cursor position. If the format being added is a
+ * visible format, add it *before* the cursor position, otherwise, add it after.
+ * This behavior is because visible formats are like characters and invisible
+ * should be stacked in a way that the last one is added last.
+ * If the format is visible the cursor is advanced after it.
+ *
+ * This function works with native formats, that means that style defined
+ * tags like <br> won't work here. For those kind of things use markup prepend.
+ *
+ * @param cur the cursor to where to add format at.
+ * @param format the format to add.
+ * @return Returns true if a visible format was added, false otherwise.
+ * @see evas_textblock_cursor_format_prepend()
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Delete the character at the location of the cursor. If there's a format
+ * pointing to this position, delete it as well.
+ *
+ * @param cur the cursor pointing to the current location.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Delete the range between cur1 and cur2.
+ *
+ * @param cur1 one side of the range.
+ * @param cur2 the second side of the range
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the text of the paragraph cur points to - returns the text in markup.
+ *
+ * @param cur the cursor pointing to the paragraph.
+ * @return the text on success, @c NULL otherwise.
+ */
+EAPI const char *evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Return the length of the paragraph, cheaper the eina_unicode_strlen()
+ *
+ * @param cur the position of the paragraph.
+ * @return the length of the paragraph on success, -1 otehrwise.
+ */
+EAPI int evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * Return the currently visible range.
+ *
+ * @param start the start of the range.
+ * @param end the end of the range.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @since 1.1
+ */
+EAPI Eina_Bool evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textblock_Cursor *end) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the format nodes in the range between cur1 and cur2.
+ *
+ * @param cur1 one side of the range.
+ * @param cur2 the other side of the range
+ * @return the foramt nodes in the range. You have to free it.
+ * @since 1.1
+ */
+EAPI Eina_List *evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the text in the range between cur1 and cur2
+ *
+ * @param cur1 one side of the range.
+ * @param cur2 the other side of the range
+ * @param format The form on which to return the text. Markup - in textblock markup. Plain - UTF8.
+ * @return the text in the range
+ * @see elm_entry_markup_to_utf8()
+ */
+EAPI char *evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the content of the cursor.
+ *
+ * Free the returned string pointer when done (if it is not NULL).
+ *
+ * @param cur the cursor
+ * @return the text in the range, terminated by a nul byte (may be utf8).
+ */
+EAPI char *evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
+
+/**
+ * Returns the geometry of two cursors ("split cursor"), if logical cursor is
+ * between LTR/RTL text, also considering paragraph direction.
+ * Upper cursor is shown for the text of the same direction as paragraph,
+ * lower cursor - for opposite.
+ *
+ * Split cursor geometry is valid only in '|' cursor mode.
+ * In this case @c EINA_TRUE is returned and cx2, cy2, cw2, ch2 are set,
+ * otherwise it behaves like cursor_geometry_get.
+ *
+ * @param[in] cur the cursor.
+ * @param[out] cx the x of the cursor (or upper cursor)
+ * @param[out] cy the y of the cursor (or upper cursor)
+ * @param[out] cw the width of the cursor (or upper cursor)
+ * @param[out] ch the height of the cursor (or upper cursor)
+ * @param[out] cx2 the x of the lower cursor
+ * @param[out] cy2 the y of the lower cursor
+ * @param[out] cw2 the width of the lower cursor
+ * @param[out] ch2 the height of the lower cursor
+ * @param[in] ctype the type of the cursor.
+ * @return @c EINA_TRUE for split cursor, @c EINA_FALSE otherwise
+ * @since 1.8
+ */
+EAPI Eina_Bool
+evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype);
+
+/**
+ * Returns the geometry of the cursor. Depends on the type of cursor requested.
+ * This should be used instead of char_geometry_get because there are weird
+ * special cases with BiDi text.
+ * in '_' cursor mode (i.e a line below the char) it's the same as char_geometry
+ * get, except for the case of the last char of a line which depends on the
+ * paragraph direction.
+ *
+ * in '|' cursor mode (i.e a line between two chars) it is very variable.
+ * For example consider the following visual string:
+ * "abcCBA" (ABC are rtl chars), a cursor pointing on A should actually draw
+ * a '|' between the c and the C.
+ *
+ * @param cur the cursor.
+ * @param cx the x of the cursor
+ * @param cy the y of the cursor
+ * @param cw the width of the cursor
+ * @param ch the height of the cursor
+ * @param dir the direction of the cursor, can be NULL.
+ * @param ctype the type of the cursor.
+ * @return line number of the char on success, -1 on error.
+ */
+EAPI int evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the geometry of the char at cur.
+ *
+ * @param cur the position of the char.
+ * @param cx the x of the char.
+ * @param cy the y of the char.
+ * @param cw the w of the char.
+ * @param ch the h of the char.
+ * @return line number of the char on success, -1 on error.
+ */
+EAPI int evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the geometry of the pen at cur.
+ *
+ * @param cur the position of the char.
+ * @param cpen_x the pen_x of the char.
+ * @param cy the y of the char.
+ * @param cadv the adv of the char.
+ * @param ch the h of the char.
+ * @return line number of the char on success, -1 on error.
+ */
+EAPI int evas_textblock_cursor_pen_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cpen_x, Evas_Coord *cy, Evas_Coord *cadv, Evas_Coord *ch) EINA_ARG_NONNULL(1);
+
+/**
+ * Returns the geometry of the line at cur.
+ *
+ * @param cur the position of the line.
+ * @param cx the x of the line.
+ * @param cy the y of the line.
+ * @param cw the width of the line.
+ * @param ch the height of the line.
+ * @return line number of the line on success, -1 on error.
+ */
+EAPI int evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
+
+/**
+ * Set the position of the cursor according to the X and Y coordinates.
+ *
+ * @param cur the cursor to set.
+ * @param x coord to set by.
+ * @param y coord to set by.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y) EINA_ARG_NONNULL(1);
+
+/**
+ * Set the cursor position according to the y coord.
+ *
+ * @param cur the cur to be set.
+ * @param y the coord to set by.
+ * @return the line number found, -1 on error.
+ */
+EAPI int evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y) EINA_ARG_NONNULL(1);
+
+/**
+ * Get the geometry of a range.
+ *
+ * @param cur1 one side of the range.
+ * @param cur2 other side of the range.
+ * @return a list of Rectangles representing the geometry of the range.
+ */
+EAPI Eina_List *evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Get the simple geometry of a range.
+ * The simple geometry is the geomtry in which rectangles in middle
+ * lines of range are merged into one big rectangle.
+ * @since 1.13
+ *
+ * @param cur1 one side of the range.
+ * @param cur2 other side of the range.
+ * @return an iterator of rectangles representing the geometry of the range.
+ */
+EAPI Eina_Iterator *evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Get the geometry of ?
+ *
+ * @param cur one side of the range.
+ * @param cur2 other side of the range.
+ */
+EAPI Eina_Bool evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
+
+/**
+ * Checks if the cursor points to the end of the line.
+ *
+ * @param cur the cursor to check.
+ * @return @c EINA_TRUE if true, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * @}
+ */
+
+/**
+ * @ingroup Evas_Object_Textblock
+ *
+ * @{
+ */
+
+/**
+ * Adds a textblock to the given evas.
+ * @param e The given evas.
+ * @return The new textblock object.
+ */
+EAPI Evas_Object *evas_object_textblock_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
+
+/**
+ * Return the plain version of the markup.
+ *
+ * Works as if you set the markup to a textblock and then retrieve the plain
+ * version of the text. i.e: <br> and <\n> will be replaced with \n, &...; with
+ * the actual char and etc.
+ *
+ * @param obj The textblock object to work with. (if @c NULL, tries the
+ * default).
+ * @param text The markup text (if @c NULL, return @c NULL).
+ * @return An allocated plain text version of the markup.
+ * @since 1.2
+ */
+EAPI char *evas_textblock_text_markup_to_utf8(const Evas_Object *obj, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
+
+/**
+ * Return the markup version of the plain text.
+ *
+ * Replaces \\n -\> \<br/\> \\t -\> \<tab/\> and etc. Generally needed before you pass
+ * plain text to be set in a textblock.
+ *
+ * @param obj the textblock object to work with (if @c NULL, it just does the
+ * default behaviour, i.e with no extra object information).
+ * @param text The plain text (if @c NULL, return @c NULL).
+ * @return An allocated markup version of the plain text.
+ * @since 1.2
+ */
+EAPI char *evas_textblock_text_utf8_to_markup(const Evas_Object *obj, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
+
+/**
+ * Clear the textblock object.
+ * @note Does *NOT* free the Evas object itself.
+ *
+ * @param obj the object to clear.
+ * @return nothing.
+ */
+EAPI void evas_object_textblock_clear(Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Sets given text as markup for the textblock object.
+ *
+ * @note assumes text does not include the unicode object replacement char (0xFFFC)
+ *
+ * @param obj the textblock object.
+ * @param text the markup text to set.
+ * @return Returns no value.
+ */
+EAPI void evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text) EINA_ARG_NONNULL(1);
+
+/**
+ * Gets the current markup text of the textblock object.
+ *
+ * @param obj the textblock object.
+ * @return Returns the current markup text.
+ */
+EAPI const char *evas_object_textblock_text_markup_get(Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Prepends markup to the cursor cur.
+ *
+ * @note assumes text does not include the unicode object replacement char (0xFFFC)
+ *
+ * @param cur the cursor to prepend to.
+ * @param text the markup text to prepend.
+ * @return Return no value.
+ */
+EAPI void evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Sets object's style to given style.
+ *
+ * @param obj the object we set the style on
+ * @param ts the style to set.
+ * @return Returns no value.
+ * @see evas_textblock_style_user_push()
+ */
+EAPI void evas_object_textblock_style_set(Evas_Object *obj, const Evas_Textblock_Style *ts) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Gets the object's current style.
+ *
+ * @param obj the object to get the style from.
+ * @return Returns the current active style.
+ * @see evas_textblock_style_user_peek()
+ */
+EAPI Evas_Textblock_Style *evas_object_textblock_style_get(const Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+
+/**
+ * Pushes ts to the top of the user style stack.
+ *
+ * FIXME: API is solid but currently only supports 1 style in the
+ * stack.
+ *
+ * The user style overrides the corresponding elements of the
+ * regular style. This is the proper way to do theme overrides
+ * in code.
+ *
+ * @param obj the object to push the style.
+ * @see also evas_textblock_style_set().
+ *
+ * @since 1.2
+ */
+EAPI void evas_object_textblock_style_user_push(Evas_Object *obj, Evas_Textblock_Style *ts) EINA_ARG_NONNULL(1,2);
+
+/**
+ * Peeks at the user-styles stack
+ *
+ * @param obj the object to get the style from.
+ * @return Returns the user style at the top of the user style stack.
+ * @see evas_textblock_style_user_pop()
+ */
+EAPI const Evas_Textblock_Style *evas_object_textblock_style_user_peek(const Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Removes the style at the top of the user-style stack
+ *
+ * @param obj the object to remove the style from.
+ * @return Returns no value.
+ * @see evas_textblock_style_user_peek()
+ */
+EAPI void evas_object_textblock_style_user_pop(Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Gets the first format node
+ *
+ * @param obj The textblock object.
+ * @return Returns the first format node.
+ */
+EAPI const Evas_Object_Textblock_Node_Format* evas_textblock_node_format_first_get(Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Gets the last format node
+ *
+ * @param obj The textblock object.
+ * @return Returns the first format node.
+ */
+EAPI const Evas_Object_Textblock_Node_Format* evas_textblock_node_format_last_get(Evas_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * Gets a list of format nodes that match given format.
+ *
+ * @param obj The textblock object to query.
+ * @param anchor The format to find in the textblock.
+ * @return Returns a list of format nodes that match the given format.
+ */
+EAPI const Eina_List *evas_textblock_node_format_list_get(const Evas_Object *obj, const char *anchor) EINA_ARG_NONNULL(1);
+
+/**
+ * Removes format node and its matching format node.
+ *
+ * @param obj The textblock object.
+ * @param n The format node to remove.
+ * @return Returns no value.
+ */
+EAPI void evas_textblock_node_format_remove_pair(Evas_Object *obj, Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Gets the geometry of the line specified by its number.
+ *
+ * @param obj The textblock object to query.
+ * @param line the line number of the queried line.
+ * @return Returns no value.
+ */
+EAPI Eina_Bool evas_object_textblock_line_number_geometry_get(const Evas_Object *obj, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1);
+
+#include "canvas/efl_canvas_text.eo.legacy.h"
+/**
+ * @}
+ */
diff --git a/src/lib/evas/canvas/efl_canvas_text.eo b/src/lib/evas/canvas/efl_canvas_text.eo
new file mode 100644
index 0000000000..fb4e198fe2
--- /dev/null
+++ b/src/lib/evas/canvas/efl_canvas_text.eo
@@ -0,0 +1,451 @@
+struct Efl.Canvas.Text.Cursor;
+struct Efl.Canvas.Text.Style;
+struct Efl.Canvas.Text.Annotation;
+
+enum Efl.Canvas.Text.Cursor_Type
+{
+ before,
+ under
+}
+
+class Efl.Canvas.Text (Evas.Object, Efl.Text)
+{
+ legacy_prefix: evas_object_textblock;
+ methods {
+ @property valign {
+ [[The vertical alignment of text within the textblock object as a whole.
+
+ Normally alignment is 0.0 (top of object). Values given should
+ be between 0.0 and 1.0 (1.0 bottom of object, 0.5 being
+ vertically centered etc.).
+
+ @since 1.1
+ ]]
+ set {}
+ get {}
+ values {
+ align: double; [[The alignment set for the object.]]
+ }
+ }
+ @property bidi_delimiters {
+ [[BiDi delimiters are used for in-paragraph separation of bidi
+ segments. This is useful for example in recipients fields of
+ e-mail clients where bidi oddities can occur when mixing RTL
+ and LTR.
+
+ @since 1.1
+ ]]
+ set {}
+ get {}
+ values {
+ delim: string; [[A null terminated string of delimiters, e.g ",|" or $null if empty.]]
+ }
+ }
+ @property replace_char {
+ [[The "replacement character" to use for the given textblock object.]]
+ set {}
+ get {}
+ values {
+ ch: string; [[The charset name.]]
+ }
+ }
+ @property legacy_newline {
+ [[When true, newline character will behave as a paragraph separator.
+
+ @since 1.1
+ ]]
+ set {}
+ get {}
+ values {
+ mode: bool; [[$true for legacy mode, $false otherwise.]]
+ }
+ }
+ @property style {
+ [[The text style of the object]]
+ set {
+ legacy: null;
+ }
+ get {
+ legacy: null;
+ }
+ values {
+ ts: string; [[The style.]]
+ }
+ }
+ @property size_formatted {
+ [[The formatted width and height.
+
+ This calculates the actual size after restricting the
+ textblock to the current size of the object.
+
+ The main difference between this and @.size_native.get
+ is that the "native" function does not wrapping into account
+ it just calculates the real width of the object if it was
+ placed on an infinite canvas, while this function gives the
+ size after wrapping according to the size restrictions of the
+ object.
+
+ For example for a textblock containing the text:
+ "You shall not pass!" with no margins or padding and assuming
+ a monospace font and a size of 7x10 char widths (for simplicity)
+ has a native size of 19x1 and a formatted size of 5x4.
+ ]]
+ get {}
+ values {
+ w: Evas.Coord; [[The width of the object.]]
+ h: Evas.Coord; [[The height of the object.]]
+ }
+ }
+ @property cursor {
+ [[The object's main cursor.]]
+ get {
+ return: Efl.Canvas.Text.Cursor *;
+ }
+ }
+ @property size_native {
+ [[The native width and height.
+
+ This calculates the actual size without taking account the
+ current size of the object.
+
+ The main difference between this and @.size_formatted.get
+ is that the "native" function does not take wrapping into
+ account it just calculates the real width of the object if
+ it was placed on an infinite canvas, while the "formatted"
+ function gives the size after wrapping text according to
+ the size restrictions of the object.
+
+ For example for a textblock containing the text:
+ "You shall not pass!" with no margins or padding and assuming
+ a monospace font and a size of 7x10 char widths (for simplicity)
+ has a native size of 19x1 and a formatted size of 5x4.
+ ]]
+ get {}
+ values {
+ w: Evas.Coord; [[The width returned.]]
+ h: Evas.Coord; [[The height returned.]]
+ }
+ }
+ @property style_insets {
+ get {}
+ values {
+ l: Evas.Coord;
+ r: Evas.Coord;
+ t: Evas.Coord;
+ b: Evas.Coord;
+ }
+ }
+ style_user_pop {
+ [[Del the from the top of the user style stack.
+
+ See also @.style.get.
+
+ @since 1.2
+ ]]
+ legacy: null;
+ }
+ cursor_new @const {
+ [[Create a new cursor, associate it to the obj and init it to point
+ to the start of the textblock.
+
+ Association to the object means the cursor will be updated when
+ the object will change.
+
+ Note: if you need speed and you know what you are doing, it's
+ slightly faster to just allocate the cursor yourself and not
+ associate it. (only people developing the actual object, and
+ not users of the object).
+ ]]
+ return: Efl.Canvas.Text.Cursor *; [[The new cursor.]]
+ }
+ style_user_peek @const {
+ [[Get (don't remove) the style at the top of the user style stack.
+
+ See also @.style.get.
+
+ @since 1.2
+ ]]
+ legacy: null;
+ return: string; [[The style of the object.]]
+ }
+ style_user_push {
+ [[Push ts to the top of the user style stack.
+
+ FIXME: API is solid but currently only supports 1 style in the
+ stack.
+
+ The user style overrides the corresponding elements of the
+ regular style. This is the proper way to do theme overrides
+ in code.
+
+ See also @.style.set.
+
+ @since 1.2
+ ]]
+ legacy: null;
+ params {
+ @in style: string; [[The style to set.]]
+ }
+ }
+ obstacle_add {
+ [[Add obstacle evas object $eo_obs to be observed during layout
+ of text.
+
+ The textblock does the layout of the text according to the
+ position of the obstacle.
+
+ @since 1.15
+ ]]
+ params {
+ @in eo_obs: Evas.Object;
+ }
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ obstacle_del {
+ [[Removes $eo_obs from observation during text layout.
+
+ @since 1.15
+ ]]
+ params {
+ @in eo_obs: Evas.Object;
+ }
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ obstacles_update {
+ [[Triggers for relayout due to obstacles' state change.
+
+ The obstacles alone don't affect the layout, until this is
+ called. Use this after doing changes (moving, positioning etc.)
+ in the obstacles that you would like to be considered in the
+ layout.
+
+ For example: if you have just repositioned the obstacles to
+ differrent coordinates relative to the textblock, you need to
+ call this so it will consider this new state and will relayout
+ the text.
+
+ @since 1.15
+ ]]
+ }
+ cursor_pos_set {
+ [[Sets position of cursor to given pos. ]]
+ legacy: null;
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[Cursor to the object.]]
+ @in pos: int; [[Position in the text to move the cursor.]]
+ }
+ }
+ cursor_text_append {
+ [[Adds text to the current cursor position and set the cursor to *before*
+ the start of the text just added.
+ ]]
+ legacy: null;
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[Cursor to the object.]]
+ @in text: string; [[Text to append (UTF-8 format).]]
+ }
+ return: int; [[Length of the appended text.]]
+ }
+ cursor_char_delete {
+ [[Deletes a single character from position pointed by given cursor.]]
+ legacy: null;
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[Cursor to the object.]]
+ }
+ }
+ cursor_free {
+ [[Free the cursor and unassociate it from the object.
+
+ Note: do not use it to free unassociated cursors.]]
+
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[The cursor to free.]]
+ }
+ }
+ cursor_compare {
+ [[Compares two cursors.
+
+ Note that 0 will be returned if they are cursors of different
+ textblock objects.
+ ]]
+ return: int; [[-1 if cur1 < cur2, 0 if cur1 == cur2, 1 otherwise.]]
+ params {
+ @in cur1: const(Efl.Canvas.Text.Cursor)*; [[The first cursor.]]
+ @in cur2: const(Efl.Canvas.Text.Cursor)*; [[The second cursor.]]
+ }
+ }
+ cursor_char_coord_set {
+ [[Sets the position of the cursor according to the X and Y
+ coordinates.]]
+ return: bool; [[$true on success, $false otherwise.]]
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[The cursor to be set.]]
+ @in x: Evas.Coord; [[x coord to set by.]]
+ @in y: Evas.Coord; [[y coord to set by.]]
+ }
+ }
+ @property annotation {
+ [[A new format for $annotation.
+
+ This will replace the format applied by $annotation with $format.
+ Assumes that $annotation is a handle for an existing annotation,
+ i.e. one that was added using @.annotation_insert to this object.
+ Otherwise, this will fail and return $false.
+
+ @since 1.18
+ ]]
+ set {
+ legacy: null;
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ get {
+ legacy: null;
+ }
+ keys {
+ annotation: Efl.Canvas.Text.Annotation *;
+ }
+ values {
+ format: string;
+ }
+ }
+ annotation_in_range_get {
+ [[Returns an iterator of all the handles in a range.
+
+ @since 1.18
+ ]]
+ legacy: null;
+ params {
+ @in start: const(Efl.Canvas.Text.Cursor)*;
+ @in end: const(Efl.Canvas.Text.Cursor)*;
+ }
+ return: free(own(iterator<Efl.Canvas.Text.Annotation *>),
+ eina_iterator_free); [[Handle of the Annotation]]
+ }
+ annotation_del {
+ [[Deletes $annotation.
+
+ All formats applied by $annotations will be removed and it will be
+ deleted.
+ ]]
+ legacy: null;
+ params {
+ @in annotation: Efl.Canvas.Text.Annotation *;
+ }
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ annotation_insert {
+ [[Inserts an annotation format in a specified range [$start, $end - 1].
+
+ This will add both opening and closing formats for the given
+ $format.
+ Returns a handle to manipulate the inserted annotation.
+
+ @since 1.18
+ ]]
+ legacy: null;
+ params {
+ @in start: Efl.Canvas.Text.Cursor *;
+ @in end: Efl.Canvas.Text.Cursor *;
+ @in format: string;
+ }
+ return: Efl.Canvas.Text.Annotation *;
+ }
+ object_item_insert {
+ [[Inserts a object item at specified position.
+
+ This adds a placeholder to be queried by higher-level code,
+ which in turn place graphics on top of it. It essentially places an
+ OBJECT REPLACEMENT CHARACTER and set a special annotation to it.
+ ]]
+ legacy: null;
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[Position of the inserted item.]]
+ @in format: string; [[Format of the inserted item.
+ See Format styles.]]
+ }
+ return: Efl.Canvas.Text.Annotation *; [[The annotation handle of the
+ inserted item.]]
+ }
+ cursor_geometry_get {
+ [[Returns the geometry of two cursors ("split cursor"), if logical cursor is
+ between LTR/RTL text, also considering paragraph direction.
+ Upper cursor is shown for the text of the same direction as paragraph,
+ lower cursor - for opposite.
+
+ Split cursor geometry is valid only in '|' cursor mode.
+ In this case $true is returned and $cx2, $cy2, $cw2, $ch2 are set.
+ ]]
+ legacy: null;
+ params {
+ @in cur: const(Efl.Canvas.Text.Cursor)*; [[ the cursor.]]
+ @in ctype: Efl.Canvas.Text.Cursor_Type; [[ the type of the cursor.]]
+ @out cx: Evas.Coord; [[the x of the cursor (or upper cursor)]]
+ @out cy: Evas.Coord; [[the y of the cursor (or upper cursor)]]
+ @out cw: Evas.Coord; [[the width of the cursor (or upper cursor)]]
+ @out ch: Evas.Coord; [[the height of the cursor (or upper cursor)]]
+ @out cx2: Evas.Coord; [[ the x of the lower cursor]]
+ @out cy2: Evas.Coord; [[ the y of the lower cursor]]
+ @out cw2: Evas.Coord; [[ the width of the lower cursor]]
+ @out ch2: Evas.Coord; [[ the height of the lower cursor]]
+ }
+ return: bool; [[ $true if split cursor, $false otherwise.]]
+ }
+ cursor_range_geometry_get {
+ [[Get the geometry of a range. The geometry is the geometry in
+ which rectangles in middle lines of range are merged into one big
+ rectangle.
+
+ @since 1.13
+ ]]
+ legacy: null;
+ params {
+ @in cur1: const(Efl.Canvas.Text.Cursor)*;
+ @in cur2: const(Efl.Canvas.Text.Cursor)*;
+ }
+ return: free(own(iterator<Eina.Rectangle>),
+ eina_iterator_free);
+ }
+ cursor_copy {
+ [[Copies source cursor to destination cursor.]]
+ legacy: null;
+ params {
+ @in dst: Efl.Canvas.Text.Cursor *; [[Destination cursor.]]
+ @in src: const(Efl.Canvas.Text.Cursor)*; [[Cursor to copy.]]
+ }
+ }
+ cursor_text_prepend {
+ [[Adds text to the current cursor position and set the cursor to *after*
+ the start of the text just added.
+ ]]
+ legacy: null;
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[Cursor to the object.]]
+ @in text: string; [[Text to append (UTF-8 format).]]
+ }
+ return: int; [[Length of the appended text.]]
+ }
+ cursor_char_prev {
+ [[Advances the cursor one char backwards.]]
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[The cursor to advance.]]
+ }
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ cursor_char_next {
+ [[Advances the cursor one char forward.]]
+ params {
+ @in cur: Efl.Canvas.Text.Cursor *; [[The cursor to advance.]]
+ }
+ return: bool; [[$true on success, $false otherwise.]]
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ Eo.Base.dbg_info_get;
+ Evas.Object.paragraph_direction.set;
+ Evas.Object.paragraph_direction.get;
+ Efl.Text.text.set;
+ Efl.Text.text.get;
+ }
+}
diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c
index 51ef647d87..8e87709922 100644
--- a/src/lib/evas/canvas/evas_object_textblock.c
+++ b/src/lib/evas/canvas/evas_object_textblock.c
@@ -67,9 +67,9 @@
//#define LYDBG(f, args...) printf(f, ##args)
#define LYDBG(f, args...)
-#define MY_CLASS EVAS_TEXTBLOCK_CLASS
+#define MY_CLASS EFL_CANVAS_TEXT_CLASS
-#define MY_CLASS_NAME "Evas_Textblock"
+#define MY_CLASS_NAME "Efl Canvas Text"
#include "linebreak.h"
#include "wordbreak.h"
@@ -136,10 +136,10 @@ static const char o_type[] = "textblock";
/* private struct for textblock object internal data */
/**
* @internal
- * @typedef Evas_Textblock_Data
+ * @typedef Efl_Canvas_Text_Data
* The actual textblock object.
*/
-typedef struct _Evas_Object_Textblock Evas_Textblock_Data;
+typedef struct _Evas_Object_Textblock Efl_Canvas_Text_Data;
/**
* @internal
* @typedef Evas_Object_Style_Tag
@@ -162,6 +162,7 @@ typedef struct _Evas_Object_Textblock_Node_Text Evas_Object_Textblock_Node_Tex
* Defined in Evas.h
typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format;
*/
+typedef struct _Evas_Textblock_Node_Format Evas_Textblock_Node_Format;
/**
* @internal
@@ -207,6 +208,12 @@ typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format;
typedef struct _Evas_Textblock_Selection_Iterator Evas_Textblock_Selection_Iterator;
/**
* @internal
+ * @typedef Efl_Canvas_Text_Annotation_Iterator
+ * A textblock annotation iterator.
+ */
+typedef struct _Efl_Canvas_Text_Annotation_Iterator Efl_Canvas_Text_Annotation_Iterator;
+/**
+ * @internal
* @def IS_AT_END(ti, ind)
* Return true if ind is at the end of the text item, false otherwise.
*/
@@ -298,6 +305,7 @@ struct _Evas_Textblock_Node_Format
const char *format; /**< Cached, parsed and translated version of orig_format. */
const char *orig_format; /**< Original format information. */
Evas_Object_Textblock_Node_Text *text_node; /**< The text node it's pointing to. */
+ Efl_Canvas_Text_Annotation *annotation; /**< Pointer to this node's annotation handle (if exists). */
size_t offset; /**< Offset from the last format node of the same text. */
struct {
unsigned char l, r, t, b;
@@ -463,7 +471,7 @@ struct _Evas_Object_Textblock_Format
Eina_Bool halign_auto : 1; /**< EINA_TRUE if auto horizontal align, else EINA_FALSE */
};
-struct _Evas_Textblock_Style
+struct _Efl_Canvas_Text_Style
{
const char *style_text;
char *default_tag;
@@ -472,20 +480,30 @@ struct _Evas_Textblock_Style
Eina_Bool delete_me : 1;
};
-struct _Evas_Textblock_Cursor
+struct _Efl_Canvas_Text_Cursor
{
Evas_Object *obj;
size_t pos;
Evas_Object_Textblock_Node_Text *node;
};
+struct _Efl_Canvas_Text_Annotation
+{
+ EINA_INLIST;
+ Evas_Object *obj;
+ Evas_Object_Textblock_Node_Format *start_node, *end_node;
+ Eina_Bool is_item : 1; /**< indicates it is an item/object placeholder */
+};
+
/* Size of the index array */
#define TEXTBLOCK_PAR_INDEX_SIZE 10
struct _Evas_Object_Textblock
{
Evas_Textblock_Style *style;
Evas_Textblock_Style *style_user;
- Evas_Textblock_Cursor *cursor;
+ Evas_Textblock_Style *current_style;
+ Evas_Textblock_Style *current_user_style;
+ Efl_Canvas_Text_Cursor *cursor;
Eina_List *cursors;
Evas_Object_Textblock_Node_Text *text_nodes;
Evas_Object_Textblock_Node_Format *format_nodes;
@@ -500,12 +518,14 @@ struct _Evas_Object_Textblock
Eina_List *anchors_item;
Eina_List *obstacles;
Eina_List *hyphen_items; /* Hyphen items storage to free when clearing lines */
+ Efl_Canvas_Text_Annotation *annotations; /* All currently applied annotations on the text. */
int last_w, last_h;
struct {
int l, r, t, b;
} style_pad;
double valign;
Eina_Stringshare *markup_text;
+ char *utf8;
void *engine_data;
const char *repch;
const char *bidi_delimiters;
@@ -533,6 +553,13 @@ struct _Evas_Textblock_Selection_Iterator
Eina_List *current; /**< Current node in loop. */
};
+struct _Efl_Canvas_Text_Annotation_Iterator
+{
+ Eina_Iterator iterator; /**< Eina Iterator. */
+ Eina_List *list; /**< Head of list. */
+ Eina_List *current; /**< Current node in loop. */
+};
+
/* private methods for textblock objects */
static void evas_object_textblock_init(Evas_Object *eo_obj);
static void evas_object_textblock_render(Evas_Object *eo_obj,
@@ -599,7 +626,7 @@ static const Evas_Object_Func object_func =
MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); \
return; \
MAGIC_CHECK_END(); \
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
#define TB_HEAD_RETURN(x) \
MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); \
@@ -607,16 +634,18 @@ static const Evas_Object_Func object_func =
MAGIC_CHECK_END();
static Eina_Bool _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur);
-static void _evas_textblock_node_text_remove(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Text *n);
-static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur);
+static void _evas_textblock_node_text_remove(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Text *n);
+static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur, Eina_Bool legacy);
static size_t _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt);
-static void _evas_textblock_node_format_remove(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment);
-static void _evas_textblock_node_format_free(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Format *n);
+static void _evas_textblock_node_format_remove(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment);
+static void _evas_textblock_node_format_free(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Format *n);
static void _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n);
-static void _evas_textblock_changed(Evas_Textblock_Data *o, Evas_Object *eo_obj);
-static void _evas_textblock_invalidate_all(Evas_Textblock_Data *o);
-static void _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset);
-static void _evas_textblock_cursors_set_node(Evas_Textblock_Data *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node);
+static void _evas_textblock_changed(Efl_Canvas_Text_Data *o, Evas_Object *eo_obj);
+static void _evas_textblock_invalidate_all(Efl_Canvas_Text_Data *o);
+static void _evas_textblock_cursors_update_offset(const Efl_Canvas_Text_Cursor *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset);
+static void _evas_textblock_cursors_set_node(Efl_Canvas_Text_Data *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node);
+static void _evas_textblock_annotations_clear(Efl_Canvas_Text_Data *o);
+static void _evas_textblock_annotation_remove(Efl_Canvas_Text_Data *o, Efl_Canvas_Text_Annotation *an, Eina_Bool remove_nodes);
#ifdef HAVE_HYPHEN
@@ -799,7 +828,11 @@ _style_match_tag(const Evas_Textblock_Style *ts, const char *s, size_t tag_len,
static void
_nodes_clear(const Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+
+ /* First, clear all annotations that may have spawned format nodes. */
+ _evas_textblock_annotations_clear(o);
+
while (o->text_nodes)
{
Evas_Object_Textblock_Node_Text *n;
@@ -1100,7 +1133,7 @@ _is_white(Eina_Unicode c)
* @param[in] p end of the string
*/
static void
-_prepend_text_run(Evas_Textblock_Cursor *cur, const char *s, const char *p)
+_prepend_text_run(Efl_Canvas_Text_Cursor *cur, const char *s, const char *p)
{
if ((s) && (p > s))
{
@@ -2315,7 +2348,7 @@ _format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const ch
fmt->ellipsis = -1.0;
else
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
o->have_ellipsis = 1;
}
}
@@ -2598,7 +2631,7 @@ typedef struct _Ctxt Ctxt;
struct _Ctxt
{
Evas_Object *obj;
- Evas_Textblock_Data *o;
+ Efl_Canvas_Text_Data *o;
Evas_Object_Textblock_Paragraph *paragraphs;
Evas_Object_Textblock_Paragraph *par;
@@ -2820,7 +2853,7 @@ _layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt)
}
static inline Evas_Object_Textblock_Paragraph *
-_layout_find_paragraph_by_y(Evas_Textblock_Data *o, Evas_Coord y)
+_layout_find_paragraph_by_y(Efl_Canvas_Text_Data *o, Evas_Coord y)
{
Evas_Object_Textblock_Paragraph *start, *par;
int i;
@@ -2846,7 +2879,7 @@ _layout_find_paragraph_by_y(Evas_Textblock_Data *o, Evas_Coord y)
}
static inline Evas_Object_Textblock_Paragraph *
-_layout_find_paragraph_by_line_no(Evas_Textblock_Data *o, int line_no)
+_layout_find_paragraph_by_line_no(Efl_Canvas_Text_Data *o, int line_no)
{
Evas_Object_Textblock_Paragraph *start, *par;
int i;
@@ -2920,7 +2953,7 @@ _layout_paragraph_new(Ctxt *c, Evas_Object_Textblock_Node_Text *n,
* @param par The paragraph to update
*/
static inline void
-_layout_update_bidi_props(const Evas_Textblock_Data *o,
+_layout_update_bidi_props(const Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Paragraph *par)
{
if (par->text_node)
@@ -2972,7 +3005,7 @@ static void
_paragraph_clear(const Evas_Object *obj,
Evas_Object_Textblock_Paragraph *par)
{
- Evas_Textblock_Data *o = eo_data_scope_get(obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(obj, MY_CLASS);
while (par->lines)
{
@@ -3009,7 +3042,7 @@ _paragraph_clear(const Evas_Object *obj,
static void
_paragraph_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Paragraph *par)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
_paragraph_clear(eo_obj, par);
{
@@ -3062,7 +3095,7 @@ _paragraphs_clear(const Evas_Object *eo_obj, Evas_Object_Textblock_Paragraph *pa
static void
_paragraphs_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Paragraph *pars)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
o->num_paragraphs = 0;
@@ -4239,9 +4272,10 @@ _layout_do_format(const Evas_Object *obj EINA_UNUSED, Ctxt *c,
const char *s;
const char *item;
int handled = 0;
+ Eina_Bool is_item = (n->annotation && n->annotation->is_item && n->opener);
s = n->format;
- if (!strncmp(s, "item ", 5))
+ if (!strncmp(s, "item ", 5) || is_item)
{
// one of:
// item size=20x10 href=name
@@ -4266,17 +4300,17 @@ _layout_do_format(const Evas_Object *obj EINA_UNUSED, Ctxt *c,
// don't care
//href = strstr(s, " href=");
- p = strstr(s, " vsize=");
+ p = strstr(s, is_item ? "vsize=" : " vsize=");
if (p)
{
- p += 7;
+ p += (is_item ? 6 : 7);
if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL;
else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT;
}
- p = strstr(s, " size=");
+ p = strstr(s, is_item ? "size=" : " size=");
if (p)
{
- p += 6;
+ p += (is_item ? 5 : 6);
if (sscanf(p, "%ix%i", &w, &h) == 2)
{
/* this is handled somewhere else because it depends
@@ -4288,10 +4322,10 @@ _layout_do_format(const Evas_Object *obj EINA_UNUSED, Ctxt *c,
}
else
{
- p = strstr(s, " absize=");
+ p = strstr(s, is_item ? "absize=" : " absize=");
if (p)
{
- p += 8;
+ p += (is_item ? 7 : 8);
if (sscanf(p, "%ix%i", &w, &h) == 2)
{
size = SIZE_ABS;
@@ -4299,7 +4333,7 @@ _layout_do_format(const Evas_Object *obj EINA_UNUSED, Ctxt *c,
}
else
{
- p = strstr(s, " relsize=");
+ p = strstr(s, is_item ? "relsize=" : " relsize=");
if (p)
{
/* this is handled somewhere else because it depends
@@ -4915,7 +4949,7 @@ _layout_handle_ellipsis(Ctxt *c, Evas_Object_Textblock_Item *it, Eina_List *i)
/* Don't do much for the meanwhile. */
static inline void
-_layout_paragraph_render(Evas_Textblock_Data *o,
+_layout_paragraph_render(Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Paragraph *par)
{
if (par->rendered)
@@ -5730,7 +5764,7 @@ _layout_pre(Ctxt *c, int *style_pad_l, int *style_pad_r, int *style_pad_t,
int *style_pad_b)
{
Evas_Object *eo_obj = c->obj;
- Evas_Textblock_Data *o = c->o;
+ Efl_Canvas_Text_Data *o = c->o;
/* Mark text nodes as dirty if format have changed. */
if (o->format_changed)
@@ -5931,7 +5965,7 @@ static void
_layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Evas_Textblock_Data *o = eo_data_ref(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_ref(eo_obj, MY_CLASS);
Ctxt ctxt, *c;
int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0;
@@ -6121,7 +6155,7 @@ static void
_relayout(const Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
_layout(eo_obj, obj->cur->geometry.w, obj->cur->geometry.h,
&o->formatted.w, &o->formatted.h);
o->formatted.valid = 1;
@@ -6152,7 +6186,7 @@ _relayout(const Evas_Object *eo_obj)
* Check if the object needs a relayout, and if so, execute it.
*/
static inline void
-_relayout_if_needed(Evas_Object *eo_obj, const Evas_Textblock_Data *o)
+_relayout_if_needed(Evas_Object *eo_obj, const Efl_Canvas_Text_Data *o)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
@@ -6180,7 +6214,7 @@ _find_layout_item_line_match(Evas_Object *eo_obj, Evas_Object_Textblock_Node_Tex
{
Evas_Object_Textblock_Paragraph *found_par;
Evas_Object_Textblock_Line *ln;
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
_relayout_if_needed(eo_obj, o);
@@ -6237,7 +6271,7 @@ _find_layout_line_num(const Evas_Object *eo_obj, int line)
{
Evas_Object_Textblock_Paragraph *par;
Evas_Object_Textblock_Line *ln;
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
par = _layout_find_paragraph_by_line_no(o, line);
if (par)
@@ -6257,15 +6291,15 @@ evas_object_textblock_add(Evas *e)
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return NULL;
MAGIC_CHECK_END();
- Evas_Object *eo_obj = eo_add(EVAS_TEXTBLOCK_CLASS, e);
+ Evas_Object *eo_obj = eo_add(MY_CLASS, e);
return eo_obj;
}
EOLIAN static Eo *
-_evas_textblock_eo_base_constructor(Eo *eo_obj, Evas_Textblock_Data *class_data EINA_UNUSED)
+_efl_canvas_text_eo_base_constructor(Eo *eo_obj, Efl_Canvas_Text_Data *class_data EINA_UNUSED)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Evas_Textblock_Data *o;
+ Efl_Canvas_Text_Data *o;
eo_obj = eo_constructor(eo_super(eo_obj, MY_CLASS));
@@ -6275,7 +6309,7 @@ _evas_textblock_eo_base_constructor(Eo *eo_obj, Evas_Textblock_Data *class_data
obj->type = o_type;
o = obj->private_data;
- o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor));
+ o->cursor = calloc(1, sizeof(Efl_Canvas_Text_Cursor));
_format_command_init();
evas_object_textblock_init(eo_obj);
@@ -6318,7 +6352,7 @@ evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text)
EINA_LIST_FOREACH(ts->objects, l, eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
_evas_textblock_invalidate_all(o);
@@ -6455,7 +6489,7 @@ evas_textblock_style_get(const Evas_Textblock_Style *ts)
}
static const char *
-_textblock_format_node_from_style_tag(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Format *fnode, const char *format, size_t format_len)
+_textblock_format_node_from_style_tag(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Format *fnode, const char *format, size_t format_len)
{
const char *match;
size_t replace_len;
@@ -6543,44 +6577,120 @@ _textblock_style_generic_set(Evas_Object *eo_obj, Evas_Textblock_Style *ts,
_evas_textblock_changed(o, eo_obj);
}
-EOLIAN static void
-_evas_textblock_style_set(Eo *eo_obj, Evas_Textblock_Data *o, const Evas_Textblock_Style *ts)
+EAPI void
+evas_object_textblock_style_set(Eo *eo_obj, const Evas_Textblock_Style *ts)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
_textblock_style_generic_set(eo_obj, (Evas_Textblock_Style *) ts, &(o->style));
}
-EOLIAN static const Evas_Textblock_Style*
-_evas_textblock_style_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+EOLIAN static void
+_efl_canvas_text_style_set(Eo *eo_obj, Efl_Canvas_Text_Data *o, const char *style)
{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+
+ if (!o->current_style)
+ {
+ Evas_Textblock_Style *ts = evas_textblock_style_new();
+ evas_textblock_style_set(ts, style);
+ _textblock_style_generic_set(eo_obj, (Evas_Textblock_Style *) ts, &(o->style));
+ o->current_style = ts;
+ }
+ else
+ {
+ evas_textblock_style_set(o->current_style, style);
+ }
+}
+
+EAPI Evas_Textblock_Style *
+evas_object_textblock_style_get(const Eo *eo_obj EINA_UNUSED)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->style;
}
-EOLIAN static void
-_evas_textblock_style_user_push(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Textblock_Style *ts)
+EOLIAN static const char *
+_efl_canvas_text_style_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
+{
+ return o->style->style_text;
+}
+
+EAPI void
+evas_object_textblock_style_user_push(Eo *eo_obj, Evas_Textblock_Style *ts)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
_textblock_style_generic_set(eo_obj, ts, &(o->style_user));
}
-EOLIAN static const Evas_Textblock_Style*
-_evas_textblock_style_user_peek(const Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+EOLIAN static void
+_efl_canvas_text_style_user_push(Eo *eo_obj, Efl_Canvas_Text_Data *o, const char *style)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+
+ if (!o->current_user_style)
+ {
+ Evas_Textblock_Style *ts = evas_textblock_style_new();
+ evas_textblock_style_set(ts, style);
+ _textblock_style_generic_set(eo_obj, (Evas_Textblock_Style *) ts, &(o->style_user));
+ o->current_user_style = ts;
+ }
+ else
+ {
+ evas_textblock_style_set(o->current_user_style, style);
+ }
+}
+
+EAPI const Evas_Textblock_Style*
+evas_object_textblock_style_user_peek(const Eo *eo_obj)
{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->style_user;
}
+EOLIAN static const char *
+_efl_canvas_text_style_user_peek(const Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
+{
+ return o->style_user ? o->style_user->style_text : NULL;
+}
+
+EAPI void
+evas_object_textblock_style_user_pop(Eo *eo_obj)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ _textblock_style_generic_set(eo_obj, NULL, &(o->style_user));
+}
+
EOLIAN static void
-_evas_textblock_style_user_pop(Eo *eo_obj, Evas_Textblock_Data *o)
+_efl_canvas_text_style_user_pop(Eo *eo_obj, Efl_Canvas_Text_Data *o)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
_textblock_style_generic_set(eo_obj, NULL, &(o->style_user));
+ if (o->current_user_style)
+ {
+ // XXX: remember that the current implementation of user style is still
+ // lacking as we don't really manage a stack.
+ // Until that's fixed, we are treating it as there can be only one
+ // user style.
+ evas_textblock_style_free(o->current_user_style);
+ o->current_user_style = NULL;
+ }
}
EOLIAN static void
-_evas_textblock_replace_char_set(Eo *eo_obj, Evas_Textblock_Data *o, const char *ch)
+_efl_canvas_text_replace_char_set(Eo *eo_obj, Efl_Canvas_Text_Data *o, const char *ch)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -6592,7 +6702,7 @@ _evas_textblock_replace_char_set(Eo *eo_obj, Evas_Textblock_Data *o, const char
}
EOLIAN static void
-_evas_textblock_legacy_newline_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o, Eina_Bool mode)
+_efl_canvas_text_legacy_newline_set(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o, Eina_Bool mode)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -6605,13 +6715,13 @@ _evas_textblock_legacy_newline_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *
}
EOLIAN static Eina_Bool
-_evas_textblock_legacy_newline_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+_efl_canvas_text_legacy_newline_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
{
return o->legacy_newline;
}
EOLIAN static void
-_evas_textblock_valign_set(Eo *eo_obj, Evas_Textblock_Data *o, double align)
+_efl_canvas_text_valign_set(Eo *eo_obj, Efl_Canvas_Text_Data *o, double align)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -6623,13 +6733,13 @@ _evas_textblock_valign_set(Eo *eo_obj, Evas_Textblock_Data *o, double align)
}
EOLIAN static double
-_evas_textblock_valign_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+_efl_canvas_text_valign_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
{
return o->valign;
}
EOLIAN static void
-_evas_textblock_bidi_delimiters_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o, const char *delim)
+_efl_canvas_text_bidi_delimiters_set(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o, const char *delim)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -6637,13 +6747,13 @@ _evas_textblock_bidi_delimiters_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data
}
EOLIAN static const char*
-_evas_textblock_bidi_delimiters_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+_efl_canvas_text_bidi_delimiters_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
{
return o->bidi_delimiters;
}
EOLIAN static const char*
-_evas_textblock_replace_char_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+_efl_canvas_text_replace_char_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
{
return o->repch;
}
@@ -6836,7 +6946,7 @@ evas_textblock_string_escape_get(const char *string, int *len_ret)
* @param s_end the end of the string.
*/
static inline void
-_prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
+_prepend_escaped_char(Efl_Canvas_Text_Cursor *cur, const char *s,
const char *s_end)
{
const char *escape;
@@ -6847,12 +6957,12 @@ _prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
}
-EOLIAN static void
-_evas_textblock_text_markup_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o, const char *text)
+EAPI void
+evas_object_textblock_text_markup_set(Eo *eo_obj, const char *text)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
-
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (text == o->markup_text)
{
/* Text is the same and already stringshared, do nothing */
@@ -6882,7 +6992,7 @@ _evas_textblock_text_markup_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o,
/* Point all the cursors to the starrt */
{
Eina_List *l;
- Evas_Textblock_Cursor *data;
+ Efl_Canvas_Text_Cursor *data;
evas_textblock_cursor_paragraph_first(o->cursor);
EINA_LIST_FOREACH(o->cursors, l, data)
@@ -6893,7 +7003,7 @@ _evas_textblock_text_markup_set(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o,
}
EAPI void
-evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text)
+evas_object_textblock_text_markup_prepend(Efl_Canvas_Text_Cursor *cur, const char *text)
{
if (!cur) return;
Evas_Object *eo_obj = cur->obj;
@@ -7097,14 +7207,15 @@ _markup_get_text_append(Eina_Strbuf *txt, const Eina_Unicode *text)
free(base);
}
-EOLIAN static const char*
-_evas_textblock_text_markup_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+EAPI const char*
+evas_object_textblock_text_markup_get(Eo *eo_obj)
{
Evas_Object_Textblock_Node_Text *n;
Eina_Strbuf *txt = NULL;
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
const char *markup;
if (o->markup_text)
{
@@ -7159,7 +7270,7 @@ _evas_textblock_text_markup_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
free(text_base);
}
- (((Evas_Textblock_Data *)o)->markup_text) = eina_stringshare_add(eina_strbuf_string_get(txt));
+ (((Efl_Canvas_Text_Data *)o)->markup_text) = eina_stringshare_add(eina_strbuf_string_get(txt));
eina_strbuf_free(txt);
markup = (o->markup_text);
@@ -7379,7 +7490,7 @@ _layout_obstacles_update(Ctxt *c)
}
static Evas_Textblock_Obstacle *
-_obstacle_find(Evas_Textblock_Data *obj, Eo *eo_obs)
+_obstacle_find(Efl_Canvas_Text_Data *obj, Eo *eo_obs)
{
Evas_Textblock_Obstacle *obs;
Eina_List *i;
@@ -7396,7 +7507,7 @@ Eina_Bool
_obstacle_del_cb(void *data, const Eo_Event *event)
{
Eo *eo_obj = data;
- Evas_Textblock_Data *obj = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *obj = eo_data_scope_get(eo_obj, MY_CLASS);
Eina_List *i;
Evas_Textblock_Obstacle *obs;
@@ -7427,7 +7538,7 @@ _obstacle_free(Eo *eo_obj, Evas_Textblock_Obstacle *obs)
}
static void
-_obstacles_free(Eo *eo_obj, Evas_Textblock_Data *obj)
+_obstacles_free(Eo *eo_obj, Efl_Canvas_Text_Data *obj)
{
Evas_Textblock_Obstacle *obs;
@@ -7438,8 +7549,8 @@ _obstacles_free(Eo *eo_obj, Evas_Textblock_Data *obj)
}
EOLIAN static Eina_Bool
-_evas_textblock_obstacle_add(Eo *eo_obj,
- Evas_Textblock_Data *obj, Eo *eo_obs)
+_efl_canvas_text_obstacle_add(Eo *eo_obj,
+ Efl_Canvas_Text_Data *obj, Eo *eo_obs)
{
Evas_Textblock_Obstacle *obs;
@@ -7462,7 +7573,7 @@ _evas_textblock_obstacle_add(Eo *eo_obj,
}
EOLIAN static Eina_Bool
-_evas_textblock_obstacle_del(Eo *eo_obj, Evas_Textblock_Data *obj,
+_efl_canvas_text_obstacle_del(Eo *eo_obj, Efl_Canvas_Text_Data *obj,
Eo *eo_obs EINA_UNUSED)
{
Evas_Textblock_Obstacle *obs;
@@ -7487,7 +7598,7 @@ _evas_textblock_obstacle_del(Eo *eo_obj, Evas_Textblock_Data *obj,
}
EOLIAN static void
-_evas_textblock_obstacles_update(Eo *eo_obj, Evas_Textblock_Data *obj)
+_efl_canvas_text_obstacles_update(Eo *eo_obj, Efl_Canvas_Text_Data *obj)
{
_evas_textblock_changed(obj, eo_obj);
obj->obstacle_changed = EINA_TRUE;
@@ -7573,7 +7684,7 @@ _layout_hyphen_item_new(Ctxt *c, const Evas_Object_Textblock_Text_Item *cur_ti)
* @param to merge into to.
*/
static void
-_evas_textblock_nodes_merge(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Text *to)
+_evas_textblock_nodes_merge(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Text *to)
{
Evas_Object_Textblock_Node_Format *itr;
Evas_Object_Textblock_Node_Format *pnode;
@@ -7641,7 +7752,7 @@ _evas_textblock_cursor_nodes_merge(Evas_Textblock_Cursor *cur)
len = eina_ustrbuf_length_get(cur->node->unicode);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next);
_evas_textblock_nodes_merge(o, cur->node);
_evas_textblock_cursors_update_offset(cur, nnode, 0, len);
@@ -7752,7 +7863,7 @@ _evas_textblock_node_visible_at_pos_get(const Evas_Object_Textblock_Node_Format
* @return the format node found.
*/
static Evas_Object_Textblock_Node_Format *
-_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur)
+_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur, Eina_Bool legacy)
{
Evas_Object_Textblock_Node_Format *node, *pitr = NULL;
Evas_Object_Textblock_Node_Format *itr;
@@ -7783,7 +7894,7 @@ _evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cur
}
else if ((position + itr->offset) == cur->pos)
{
- return itr;
+ return legacy ? itr : pitr;
}
pitr = itr;
position += itr->offset;
@@ -7802,9 +7913,9 @@ _evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cur
* otherwise.
*/
static Eina_Bool
-_find_layout_item_match(const Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
+_find_layout_item_match(const Efl_Canvas_Text_Cursor *cur, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
{
- Evas_Textblock_Cursor cur2;
+ Efl_Canvas_Text_Cursor cur2;
Eina_Bool previous_format = EINA_FALSE;
cur2.obj = cur->obj;
@@ -7827,20 +7938,20 @@ _find_layout_item_match(const Evas_Textblock_Cursor *cur, Evas_Object_Textblock_
return previous_format;
}
-EOLIAN static Evas_Textblock_Cursor*
-_evas_textblock_cursor_get(Eo *eo_obj EINA_UNUSED, Evas_Textblock_Data *o)
+EOLIAN static Efl_Canvas_Text_Cursor*
+_efl_canvas_text_cursor_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
{
return o->cursor;
}
-EOLIAN static Evas_Textblock_Cursor*
-_evas_textblock_cursor_new(const Eo *eo_obj, Evas_Textblock_Data *o)
+EOLIAN static Efl_Canvas_Text_Cursor*
+_efl_canvas_text_cursor_new(const Eo *eo_obj, Efl_Canvas_Text_Data *o)
{
- Evas_Textblock_Cursor *cur;
+ Efl_Canvas_Text_Cursor *cur;
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- cur = calloc(1, sizeof(Evas_Textblock_Cursor));
+ cur = calloc(1, sizeof(Efl_Canvas_Text_Cursor));
if (!cur) return NULL;
cur->obj = (Evas_Object *) eo_obj;
cur->node = o->text_nodes;
@@ -7853,9 +7964,16 @@ EAPI void
evas_textblock_cursor_free(Evas_Textblock_Cursor *cur)
{
if (!cur) return;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ efl_canvas_text_cursor_free(cur->obj, cur);
+}
+
+EOLIAN static void
+_efl_canvas_text_cursor_free(Eo *eo_obj, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Cursor *cur)
+{
+ if (!cur) return;
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
if (cur == o->cursor) return;
o->cursors = eina_list_remove(o->cursors, cur);
free(cur);
@@ -7871,11 +7989,12 @@ evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur)
EINA_TRUE : EINA_FALSE;
}
-EOLIAN static const Eina_List *
-_evas_textblock_node_format_list_get(const Eo *eo_obj, Evas_Textblock_Data *o, const char *anchor)
+EAPI const Eina_List *
+evas_textblock_node_format_list_get(const Eo *eo_obj, const char *anchor)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!strcmp(anchor, "a"))
return o->anchors_a;
else if (!strcmp(anchor, "item"))
@@ -7883,19 +8002,21 @@ _evas_textblock_node_format_list_get(const Eo *eo_obj, Evas_Textblock_Data *o, c
return NULL;
}
-EOLIAN static const Evas_Object_Textblock_Node_Format*
-_evas_textblock_node_format_first_get(Eo *eo_obj, Evas_Textblock_Data *o)
+EAPI const Evas_Object_Textblock_Node_Format*
+evas_textblock_node_format_first_get(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->format_nodes;
}
-EOLIAN static const Evas_Object_Textblock_Node_Format*
-_evas_textblock_node_format_last_get(Eo *eo_obj, Evas_Textblock_Data *o)
+EAPI const Evas_Object_Textblock_Node_Format*
+evas_textblock_node_format_last_get(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->format_nodes ? _NODE_FORMAT(EINA_INLIST_GET(o->format_nodes)->last) : NULL;
}
@@ -7913,8 +8034,8 @@ evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n)
return _NODE_FORMAT(EINA_INLIST_GET(n)->prev);
}
-EOLIAN static void
-_evas_textblock_node_format_remove_pair(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Format *n)
+EAPI void
+evas_textblock_node_format_remove_pair(Eo *eo_obj, Evas_Object_Textblock_Node_Format *n)
{
Evas_Object_Textblock_Node_Text *tnode1;
Evas_Object_Textblock_Node_Format *fmt, *found_node = NULL;
@@ -7926,6 +8047,7 @@ _evas_textblock_node_format_remove_pair(Eo *eo_obj, Evas_Textblock_Data *o, Evas
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
do
{
const char *fstr = fmt->orig_format;
@@ -7984,7 +8106,7 @@ found:
{
size_t ind = _evas_textblock_node_format_pos_get(n);
const char *format = n->format;
- Evas_Textblock_Cursor cur;
+ Efl_Canvas_Text_Cursor cur;
cur.obj = eo_obj;
eina_ustrbuf_remove(n->text_node->unicode, ind, ind + 1);
@@ -8027,7 +8149,7 @@ evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur)
if (!cur) return;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
cur->node = o->text_nodes;
cur->pos = 0;
@@ -8041,7 +8163,7 @@ evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur)
if (!cur) return;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
node = o->text_nodes;
if (node)
{
@@ -8127,7 +8249,7 @@ evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur)
/* If the current node is a format node, just get the next if any,
* if it's a text, get the current format node out of the text and return
* the next format node if any. */
- node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur, EINA_TRUE);
node = _evas_textblock_node_format_last_at_off(node);
if (!node)
{
@@ -8165,7 +8287,7 @@ evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur)
node = evas_textblock_cursor_format_get(cur);
if (!node)
{
- node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur, EINA_TRUE);
if (node)
{
cur->node = node->text_node;
@@ -8309,15 +8431,22 @@ evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur)
free(breaks);
return EINA_TRUE;
}
-
EAPI Eina_Bool
evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
{
+ if (!cur) return EINA_FALSE;
+ return efl_canvas_text_cursor_char_next(cur->obj, cur);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_cursor_char_next(Eo *eo_obj,
+ Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Canvas_Text_Cursor *cur)
+{
int ind;
const Eina_Unicode *text;
if (!cur) return EINA_FALSE;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
TB_NULL_CHECK(cur->node, EINA_FALSE);
@@ -8354,7 +8483,15 @@ EAPI Eina_Bool
evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
{
if (!cur) return EINA_FALSE;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ return efl_canvas_text_cursor_char_prev(cur->obj, cur);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_cursor_char_prev(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ Efl_Canvas_Text_Cursor *cur)
+{
+ if (!cur) return EINA_FALSE;
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
TB_NULL_CHECK(cur->node, EINA_FALSE);
@@ -8400,8 +8537,8 @@ evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur)
static void
_cursor_line_first_char_get(Evas_Object_Textblock_Line *ln,
- Evas_Textblock_Cursor *cur,
- Evas_Textblock_Data *o)
+ Efl_Canvas_Text_Cursor *cur,
+ Efl_Canvas_Text_Data *o)
{
if (ln->items)
{
@@ -8435,7 +8572,7 @@ evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur)
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
TB_NULL_CHECK(cur->node);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -8457,7 +8594,7 @@ evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur)
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
TB_NULL_CHECK(cur->node);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -8505,7 +8642,7 @@ evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur)
*/
static void
_evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode,
- const char *s)
+ const char *s, Eina_Bool is_item)
{
const char *item;
Eina_Bool is_opener = EINA_TRUE;
@@ -8531,7 +8668,10 @@ _evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode,
(!strncmp(item, "br", itlen) && (itlen >= 2)) ||
(!strncmp(item, "tab", itlen) && (itlen >= 3)) ||
(!strncmp(item, "ps", itlen) && (itlen >= 2)) ||
- (!strncmp(item, "item", itlen) && (itlen >= 4) && is_opener))
+ (is_opener &&
+ (is_item ||
+ (fnode->annotation && fnode->annotation->is_item) ||
+ ((!strncmp(item, "item", itlen) && (itlen >= 4))))))
{
fnode->visible = EINA_TRUE;
}
@@ -8540,7 +8680,9 @@ _evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode,
{
fnode->anchor = ANCHOR_A;
}
- else if (is_opener && !strncmp(item, "item", itlen) && (itlen >= 4))
+ else if (is_opener &&
+ ((fnode->annotation && fnode->annotation->is_item) ||
+ (!strncmp(item, "item", itlen) && (itlen >= 4))))
{
fnode->anchor = ANCHOR_ITEM;
}
@@ -8591,7 +8733,7 @@ _evas_textblock_cursor_node_text_at_format(Evas_Textblock_Cursor *cur, Evas_Obje
* @param fmt the current format.
*/
static void
-_evas_textblock_node_format_remove_matching(Evas_Textblock_Data *o,
+_evas_textblock_node_format_remove_matching(Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Node_Format *fmt)
{
Evas_Object_Textblock_Node_Text *tnode;
@@ -8641,10 +8783,20 @@ _evas_textblock_node_format_remove_matching(Evas_Textblock_Data *o,
if (_FORMAT_IS_CLOSER_OF(
fnode->orig_format, fstr + 1, fstr_len - 1))
{
+ Eina_Bool have_annotation = !!fmt->annotation;
+
fnode = eina_list_data_get(i);
formats = eina_list_remove_list(formats, i);
_evas_textblock_node_format_remove(o, fnode, 0);
_evas_textblock_node_format_remove(o, fmt, 0);
+
+ /* Only matching format nodes may be the result
+ * of an annotation. */
+ if (have_annotation)
+ {
+ _evas_textblock_annotation_remove(
+ o, fmt->annotation, EINA_FALSE);
+ }
break;
}
}
@@ -8671,7 +8823,7 @@ _evas_textblock_node_format_remove_matching(Evas_Textblock_Data *o,
* @param offset the offest to add (may be negative).
*/
static void
-_evas_textblock_node_format_adjust_offset(Evas_Textblock_Data *o,
+_evas_textblock_node_format_adjust_offset(Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Node_Text *tnode,
Evas_Object_Textblock_Node_Format *fmt, int offset)
{
@@ -8698,7 +8850,7 @@ _evas_textblock_node_format_adjust_offset(Evas_Textblock_Data *o,
* @param n the fromat node to remove
*/
static void
-_evas_textblock_node_format_remove(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Format *n, int visible_adjustment)
+_evas_textblock_node_format_remove(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Format *n, int visible_adjustment)
{
/* Update the text nodes about the change */
{
@@ -8753,7 +8905,7 @@ _evas_textblock_node_format_remove(Evas_Textblock_Data *o, Evas_Object_Textblock
* @returns @c EINA_TRUE if removed a PS, @c EINA_FALSE otherwise.
*/
static Eina_Bool
-_evas_textblock_node_text_adjust_offsets_to_start(Evas_Textblock_Data *o,
+_evas_textblock_node_text_adjust_offsets_to_start(Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Node_Text *n, size_t start, int end)
{
Evas_Object_Textblock_Node_Format *last_node, *itr;
@@ -8881,7 +9033,7 @@ _evas_textblock_node_text_get_first_format_between(
* @param n the node to remove.
*/
static void
-_evas_textblock_node_text_remove(Evas_Textblock_Data *o, Evas_Object_Textblock_Node_Text *n)
+_evas_textblock_node_text_remove(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Text *n)
{
_evas_textblock_node_text_adjust_offsets_to_start(o, n, 0, -1);
@@ -8930,7 +9082,7 @@ evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur)
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
TB_NULL_CHECK(cur->node, 0);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
n = o->text_nodes;
while (n != cur->node)
{
@@ -8943,13 +9095,20 @@ evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur)
EAPI void
evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int _pos)
{
+ if (!cur) return;
+ efl_canvas_text_cursor_pos_set(cur->obj, cur, _pos);
+}
+
+EOLIAN static void
+_efl_canvas_text_cursor_pos_set(Eo *eo_obj, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Cursor *cur, int _pos)
+{
Evas_Object_Textblock_Node_Text *n;
size_t pos;
if (!cur) return;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
if (_pos < 0)
{
@@ -8996,7 +9155,7 @@ evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line)
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -9009,13 +9168,21 @@ evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line)
}
EAPI int
-evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+evas_textblock_cursor_compare(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+{
+ if (!cur1) return 0;
+ return efl_canvas_text_cursor_compare(cur1->obj, cur1, cur2);
+}
+
+EOLIAN static int
+_efl_canvas_text_cursor_compare(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ const Efl_Canvas_Text_Cursor *cur1, const Efl_Canvas_Text_Cursor *cur2)
{
Eina_Inlist *l1, *l2;
if (!cur1) return 0;
if (!cur2) return 0;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur1->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (cur1->obj != cur2->obj) return 0;
if ((!cur1->node) || (!cur2->node)) return 0;
@@ -9039,16 +9206,24 @@ evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Text
}
EAPI void
-evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest)
+evas_textblock_cursor_copy(const Efl_Canvas_Text_Cursor *cur, Efl_Canvas_Text_Cursor *cur_dest)
{
if (!cur) return;
- if (!cur_dest) return;
- if (cur->obj != cur_dest->obj) return;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
- evas_object_async_block(obj);
- cur_dest->pos = cur->pos;
- cur_dest->node = cur->node;
+ efl_canvas_text_cursor_copy(cur->obj, cur_dest, cur);
+}
+static EOLIAN void
+_efl_canvas_text_cursor_copy(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o EINA_UNUSED,
+ Efl_Canvas_Text_Cursor *dst, const Efl_Canvas_Text_Cursor *src)
+{
+ if (!src) return;
+ if (!dst) return;
+ if (src->obj != dst->obj) return;
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(src->obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+ dst->pos = src->pos;
+ dst->node = src->node;
}
/* text controls */
@@ -9102,13 +9277,14 @@ _evas_textblock_node_text_new(void)
* @return Returns no value.
*/
static void
-_evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
- Evas_Object_Textblock_Node_Format *fnode)
+_evas_textblock_cursor_break_paragraph(Efl_Canvas_Text_Cursor *cur,
+ Evas_Object_Textblock_Node_Format *fnode,
+ Eina_Bool legacy)
{
Evas_Object_Textblock_Node_Text *n;
if (!cur) return;
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
n = _evas_textblock_node_text_new();
o->text_nodes = _NODE_TEXT(eina_inlist_append_relative(
@@ -9122,20 +9298,27 @@ _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
size_t len, start;
const Eina_Unicode *text;
+ if (legacy)
+ {
/* If there was a format node in the delete range,
* make it our format and update the text_node fields,
* otherwise, use the paragraph separator
* of the previous paragraph. */
- nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
- if (nnode && (nnode->text_node == cur->node))
- {
- n->format_node = nnode;
- nnode->offset--; /* We don't have to take the replacement char
- into account anymore */
- while (nnode && (nnode->text_node == cur->node))
+ nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
+ if (nnode && (nnode->text_node == cur->node))
+ {
+ n->format_node = nnode;
+ nnode->offset--; /* We don't have to take the replacement char
+ into account anymore */
+ while (nnode && (nnode->text_node == cur->node))
+ {
+ nnode->text_node = n;
+ nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
+ }
+ }
+ else
{
- nnode->text_node = n;
- nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
+ n->format_node = fnode;
}
}
else
@@ -9143,8 +9326,12 @@ _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
n->format_node = fnode;
}
- /* cur->pos now points to the PS, move after. */
- start = cur->pos + 1;
+ start = cur->pos;
+ if (legacy)
+ {
+ /* cur->pos now points to the PS, move after. */
+ start++;
+ }
len = eina_ustrbuf_length_get(cur->node->unicode) - start;
if (len > 0)
{
@@ -9154,7 +9341,7 @@ _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
cur->node->dirty = EINA_TRUE;
}
}
- else
+ else if (!cur->node)
{
fnode = o->format_nodes;
if (fnode)
@@ -9174,12 +9361,12 @@ _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
* @param new_node the new node to set.
*/
static void
-_evas_textblock_cursors_set_node(Evas_Textblock_Data *o,
+_evas_textblock_cursors_set_node(Efl_Canvas_Text_Data *o,
const Evas_Object_Textblock_Node_Text *n,
Evas_Object_Textblock_Node_Text *new_node)
{
Eina_List *l;
- Evas_Textblock_Cursor *data;
+ Efl_Canvas_Text_Cursor *data;
if (n == o->cursor->node)
{
@@ -9206,13 +9393,13 @@ _evas_textblock_cursors_set_node(Evas_Textblock_Data *o,
* @param offset how much to adjust (can be negative).
*/
static void
-_evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur,
+_evas_textblock_cursors_update_offset(const Efl_Canvas_Text_Cursor *cur,
const Evas_Object_Textblock_Node_Text *n,
size_t start, int offset)
{
Eina_List *l;
- Evas_Textblock_Cursor *data;
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Cursor *data;
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
if (cur != o->cursor)
{
@@ -9262,7 +9449,7 @@ _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur,
* @param obj the evas object.
*/
static void
-_evas_textblock_changed(Evas_Textblock_Data *o, Evas_Object *eo_obj)
+_evas_textblock_changed(Efl_Canvas_Text_Data *o, Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
LYDBG("ZZ: invalidate 1 %p\n", eo_obj);
@@ -9279,7 +9466,7 @@ _evas_textblock_changed(Evas_Textblock_Data *o, Evas_Object *eo_obj)
}
static void
-_evas_textblock_invalidate_all(Evas_Textblock_Data *o)
+_evas_textblock_invalidate_all(Efl_Canvas_Text_Data *o)
{
Evas_Object_Textblock_Node_Text *n;
@@ -9289,42 +9476,45 @@ _evas_textblock_invalidate_all(Evas_Textblock_Data *o)
}
}
-EAPI int
-evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
+static int
+_cursor_text_append(Eo *eo_obj, Efl_Canvas_Text_Cursor *cur, const char *_text,
+ Eina_Bool legacy)
{
Evas_Object_Textblock_Node_Text *n;
Evas_Object_Textblock_Node_Format *fnode = NULL;
- Eina_Unicode *text;
+ Eina_Unicode *text, *orig_text;
int len = 0;
if (!cur) return 0;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
text = eina_unicode_utf8_to_unicode(_text, &len);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ orig_text = text = eina_unicode_utf8_to_unicode(_text, &len);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
n = cur->node;
if (n)
{
Evas_Object_Textblock_Node_Format *nnode;
- fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur, legacy);
fnode = _evas_textblock_node_format_last_at_off(fnode);
/* find the node after the current in the same paragraph
* either we find one and then take the next, or we try to get
* the first for the paragraph which must be after our position */
- if (fnode)
+ if (fnode && fnode->annotation && fnode->annotation->is_item)
+ {
+ fnode = NULL;
+ }
+ else if (fnode)
{
- if (!evas_textblock_cursor_format_is_visible_get(cur))
+ nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
+ if (nnode && (nnode->text_node == n))
{
- nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
- if (nnode && (nnode->text_node == n))
- {
- fnode = nnode;
- }
- else
- {
- fnode = NULL;
- }
+ fnode = nnode;
+ }
+ else
+ {
+ fnode = NULL;
}
}
else
@@ -9346,7 +9536,10 @@ evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
cur->node = n;
}
- eina_ustrbuf_insert_length(n->unicode, text, len, cur->pos);
+ size_t pos = cur->pos;
+ Evas_Object_Textblock_Node_Text *nn = NULL;
+ eina_ustrbuf_insert_length(n->unicode, text, eina_unicode_strlen(text), pos);
+
/* Advance the formats */
if (fnode && (fnode->text_node == cur->node))
fnode->offset += len;
@@ -9354,9 +9547,14 @@ evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
/* Update all the cursors after our position. */
_evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, len);
+ if (nn)
+ {
+ cur->node = nn;
+ len = eina_unicode_strlen(text);
+ }
_evas_textblock_changed(o, cur->obj);
n->dirty = EINA_TRUE;
- free(text);
+ free(orig_text);
if (!o->cursor->node)
o->cursor->node = o->text_nodes;
@@ -9364,19 +9562,39 @@ evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
}
EAPI int
-evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text)
+evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
+{
+ return _cursor_text_append(cur->obj, cur, _text, EINA_TRUE);
+}
+
+static int
+_cursor_text_prepend(Eo *eo_obj, Efl_Canvas_Text_Cursor *cur, const char *_text,
+ Eina_Bool legacy)
{
int len;
/*append is essentially prepend without advancing */
if (!cur) return 0;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- len = evas_textblock_cursor_text_append(cur, _text);
+ len = _cursor_text_append(eo_obj, cur, _text, legacy);
if (len == 0) return 0;
cur->pos += len; /*Advance */
return len;
}
+EAPI int
+evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text)
+{
+ return _cursor_text_prepend(cur->obj, cur, _text, EINA_TRUE);
+}
+
+EOLIAN static int
+_efl_canvas_text_cursor_text_prepend(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ Efl_Canvas_Text_Cursor *cur, const char *_text)
+{
+ return _cursor_text_prepend(eo_obj, cur, _text, EINA_FALSE);
+}
+
/**
* @internal
* Free a format node
@@ -9385,7 +9603,7 @@ evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text
* @param n the format node to free
*/
static void
-_evas_textblock_node_format_free(Evas_Textblock_Data *o,
+_evas_textblock_node_format_free(Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Node_Format *n)
{
if (!n) return;
@@ -9407,7 +9625,8 @@ _evas_textblock_node_format_free(Evas_Textblock_Data *o,
* @return Returns the new format node
*/
static Evas_Object_Textblock_Node_Format *
-_evas_textblock_node_format_new(Evas_Textblock_Data *o, const char *_format)
+_evas_textblock_node_format_new(Efl_Canvas_Text_Data *o, const char *_format,
+ Eina_Bool is_item)
{
Evas_Object_Textblock_Node_Format *n;
const char *format = _format;
@@ -9516,7 +9735,7 @@ _evas_textblock_node_format_new(Evas_Textblock_Data *o, const char *_format)
}
format = n->format;
- _evas_textblock_format_is_visible(n, format);
+ _evas_textblock_format_is_visible(n, format, is_item);
if (n->anchor == ANCHOR_A)
{
o->anchors_a = eina_list_append(o->anchors_a, n);
@@ -9543,8 +9762,10 @@ _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur)
EINA_TRUE : EINA_FALSE;
}
-EAPI Eina_Bool
-evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
+Eina_Bool
+_evas_textblock_cursor_format_append(Efl_Canvas_Text_Cursor *cur,
+ const char *format, Evas_Object_Textblock_Node_Format **_fnode,
+ Eina_Bool is_item)
{
Evas_Object_Textblock_Node_Format *n;
Eina_Bool is_visible;
@@ -9553,14 +9774,14 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if ((!format) || (format[0] == 0)) return EINA_FALSE;
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
/* We should always have at least one text node */
if (!o->text_nodes)
{
evas_textblock_cursor_text_prepend(cur, "");
}
- n = _evas_textblock_node_format_new(o, format);
+ n = _evas_textblock_node_format_new(o, format, is_item);
is_visible = n->visible;
format = n->format;
if (!cur->node)
@@ -9577,7 +9798,7 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
else
{
Evas_Object_Textblock_Node_Format *fmt;
- fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur, EINA_TRUE);
n->text_node = cur->node;
if (!fmt)
{
@@ -9657,7 +9878,7 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
_evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1);
if (_IS_PARAGRAPH_SEPARATOR(o, format))
{
- _evas_textblock_cursor_break_paragraph(cur, n);
+ _evas_textblock_cursor_break_paragraph(cur, n, EINA_TRUE);
}
else
{
@@ -9675,10 +9896,18 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
if (!o->cursor->node)
o->cursor->node = o->text_nodes;
+
+ if (_fnode) *_fnode = n;
return is_visible;
}
EAPI Eina_Bool
+evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
+{
+ return _evas_textblock_cursor_format_append(cur, format, NULL, EINA_FALSE);
+}
+
+EAPI Eina_Bool
evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format)
{
Eina_Bool is_visible;
@@ -9700,14 +9929,21 @@ evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *for
EAPI void
evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
{
+ if (!cur) return;
+ efl_canvas_text_cursor_char_delete(cur->obj, cur);
+}
+
+EOLIAN static void
+_efl_canvas_text_cursor_char_delete(Eo *eo_obj, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Cursor *cur)
+{
Evas_Object_Textblock_Node_Text *n, *n2;
const Eina_Unicode *text;
int chr, ind, ppos;
if (!cur || !cur->node) return;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
n = cur->node;
text = eina_ustrbuf_string_get(n->unicode);
@@ -9746,7 +9982,7 @@ evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
}
}
- fmt2 = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ fmt2 = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur, EINA_TRUE);
fmt2 = _evas_textblock_node_format_last_at_off(fmt2);
_evas_textblock_node_format_adjust_offset(o, cur->node, fmt2,
-(ind - cur->pos));
@@ -9775,7 +10011,7 @@ evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
}
EAPI void
-evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
+evas_textblock_cursor_range_delete(Efl_Canvas_Text_Cursor *cur1, Evas_Textblock_Cursor *cur2)
{
Evas_Object_Textblock_Node_Format *fnode = NULL;
Evas_Object_Textblock_Node_Text *n1, *n2;
@@ -9786,10 +10022,10 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C
if (cur1->obj != cur2->obj) return;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur1->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur1->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur1->obj, MY_CLASS);
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
{
- Evas_Textblock_Cursor *tc;
+ Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = cur2;
@@ -9916,24 +10152,24 @@ evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur)
}
static char *
-_evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
+_evas_textblock_cursor_range_text_markup_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
{
Evas_Object_Textblock_Node_Text *tnode;
Eina_Strbuf *buf;
- Evas_Textblock_Cursor *cur2;
+ Efl_Canvas_Text_Cursor *cur2;
buf = eina_strbuf_new();
if (evas_textblock_cursor_compare(cur1, _cur2) > 0)
{
- const Evas_Textblock_Cursor *tc;
+ const Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = _cur2;
_cur2 = tc;
}
/* Work on a local copy of the cur */
- cur2 = alloca(sizeof(Evas_Textblock_Cursor));
+ cur2 = alloca(sizeof(Efl_Canvas_Text_Cursor));
cur2->obj = _cur2->obj;
evas_textblock_cursor_copy(_cur2, cur2);
@@ -10024,17 +10260,17 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1,
}
static char *
-_evas_textblock_cursor_range_text_plain_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
+_evas_textblock_cursor_range_text_plain_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
{
Eina_UStrbuf *buf;
Evas_Object_Textblock_Node_Text *n1, *n2;
- Evas_Textblock_Cursor *cur2;
+ Efl_Canvas_Text_Cursor *cur2;
buf = eina_ustrbuf_new();
if (evas_textblock_cursor_compare(cur1, _cur2) > 0)
{
- const Evas_Textblock_Cursor *tc;
+ const Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = _cur2;
@@ -10043,7 +10279,7 @@ _evas_textblock_cursor_range_text_plain_get(const Evas_Textblock_Cursor *cur1, c
n1 = cur1->node;
n2 = _cur2->node;
/* Work on a local copy of the cur */
- cur2 = alloca(sizeof(Evas_Textblock_Cursor));
+ cur2 = alloca(sizeof(Efl_Canvas_Text_Cursor));
cur2->obj = _cur2->obj;
evas_textblock_cursor_copy(_cur2, cur2);
@@ -10080,7 +10316,7 @@ _evas_textblock_cursor_range_text_plain_get(const Evas_Textblock_Cursor *cur1, c
}
EAPI Eina_List *
-evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+evas_textblock_cursor_range_formats_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
{
Evas_Object *eo_obj;
Eina_List *ret = NULL;
@@ -10097,7 +10333,7 @@ evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
{
- const Evas_Textblock_Cursor *tc;
+ const Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = cur2;
@@ -10151,7 +10387,7 @@ evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const
}
EAPI char *
-evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format)
+evas_textblock_cursor_range_text_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format)
{
Evas_Object_Protected_Data *obj;
@@ -10172,7 +10408,7 @@ evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Ev
EAPI const char *
evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur)
{
- Evas_Textblock_Cursor cur1, cur2;
+ Efl_Canvas_Text_Cursor cur1, cur2;
if (!cur) return NULL;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -10302,16 +10538,25 @@ _find_layout_line_by_item(Evas_Object_Textblock_Paragraph *par, Evas_Object_Text
#endif
EAPI Eina_Bool
-evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype)
+evas_textblock_cursor_geometry_bidi_get(const Efl_Canvas_Text_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype)
{
if (!cur) return EINA_FALSE;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ return efl_canvas_text_cursor_geometry_get(cur->obj, cur,
+ (ctype == EVAS_TEXTBLOCK_CURSOR_BEFORE) ?
+ EFL_CANVAS_TEXT_CURSOR_TYPE_BEFORE : EFL_CANVAS_TEXT_CURSOR_TYPE_UNDER,
+ cx, cy, cw, ch, cx2, cy2, cw2, ch2);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_cursor_geometry_get(Eo *eo_obj, Efl_Canvas_Text_Data *o, const Efl_Canvas_Text_Cursor *cur, Efl_Canvas_Text_Cursor_Type ctype, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2)
+{
+ if (!cur) return EINA_FALSE;
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
- if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER)
+ if (ctype == EFL_CANVAS_TEXT_CURSOR_TYPE_UNDER)
{
evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch);
return EINA_FALSE;
@@ -10480,18 +10725,20 @@ evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_C
(void) cw2;
(void) ch2;
#endif
- evas_textblock_cursor_geometry_get(cur, cx, cy, cw, ch, NULL, ctype);
+ evas_textblock_cursor_geometry_get(cur, cx, cy, cw, ch, NULL,
+ (ctype == EFL_CANVAS_TEXT_CURSOR_TYPE_BEFORE) ?
+ EVAS_TEXTBLOCK_CURSOR_BEFORE : EVAS_TEXTBLOCK_CURSOR_UNDER);
return EINA_FALSE;
}
EAPI int
-evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype)
+evas_textblock_cursor_geometry_get(const Efl_Canvas_Text_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype)
{
int ret = -1;
if (!cur) return -1;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -10570,7 +10817,7 @@ _evas_textblock_cursor_char_pen_geometry_common_get(int (*query_func) (void *dat
Eina_Bool previous_format;
if (!cur) return -1;
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -10704,7 +10951,7 @@ evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C
if (!cur) return -1;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -10729,7 +10976,7 @@ evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C
}
EAPI Eina_Bool
-evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textblock_Cursor *end)
+evas_textblock_cursor_visible_range_get(Efl_Canvas_Text_Cursor *start, Evas_Textblock_Cursor *end)
{
Evas *eo_e;
Evas_Coord cy, ch;
@@ -10749,16 +10996,24 @@ evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textb
}
EAPI Eina_Bool
-evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
+evas_textblock_cursor_char_coord_set(Efl_Canvas_Text_Cursor *cur, Evas_Coord x, Evas_Coord y)
+{
+ if (!cur) return EINA_FALSE;
+ return efl_canvas_text_cursor_char_coord_set(cur->obj, cur, x, y);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_cursor_char_coord_set(Eo *eo_obj,
+ Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Canvas_Text_Cursor *cur,
+ Evas_Coord x, Evas_Coord y)
{
Evas_Object_Textblock_Paragraph *found_par;
Evas_Object_Textblock_Line *ln;
Evas_Object_Textblock_Item *it = NULL;
if (!cur) return EINA_FALSE;
- Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -10881,7 +11136,7 @@ evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
if (!cur) return -1;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -11008,8 +11263,8 @@ _evas_textblock_range_calc_x_w(const Evas_Object_Textblock_Item *it,
*/
static Eina_List *
_evas_textblock_cursor_range_in_line_geometry_get(
- const Evas_Object_Textblock_Line *ln, const Evas_Textblock_Cursor *cur1,
- const Evas_Textblock_Cursor *cur2)
+ const Evas_Object_Textblock_Line *ln, const Efl_Canvas_Text_Cursor *cur1,
+ const Efl_Canvas_Text_Cursor *cur2)
{
Evas_Object_Textblock_Item *it;
Evas_Object_Textblock_Item *it1, *it2;
@@ -11017,7 +11272,7 @@ _evas_textblock_cursor_range_in_line_geometry_get(
Evas_Textblock_Rectangle *tr;
size_t start, end;
Eina_Bool switch_items;
- const Evas_Textblock_Cursor *cur;
+ const Efl_Canvas_Text_Cursor *cur;
cur = (cur1) ? cur1 : cur2;
@@ -11302,7 +11557,16 @@ _line_fill_rect_get(const Evas_Object_Textblock_Line *ln,
}
EAPI Eina_Iterator *
-evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+evas_textblock_cursor_range_simple_geometry_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+{
+ if (!cur1) return NULL;
+ return efl_canvas_text_cursor_range_geometry_get(cur1->obj, cur1, cur2);
+}
+
+static EOLIAN Eina_Iterator *
+_efl_canvas_text_cursor_range_geometry_get(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o, const Efl_Canvas_Text_Cursor *cur1, const
+ Evas_Textblock_Cursor *cur2)
{
Evas_Object_Textblock_Line *ln1, *ln2;
Evas_Object_Textblock_Item *it1, *it2;
@@ -11314,13 +11578,12 @@ evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur
if (cur1->obj != cur2->obj) return NULL;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur1->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur1->obj, MY_CLASS);
_relayout_if_needed(cur1->obj, o);
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
{
- const Evas_Textblock_Cursor *tc;
+ const Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = cur2;
@@ -11408,7 +11671,7 @@ evas_textblock_cursor_range_simple_geometry_get(const Evas_Textblock_Cursor *cur
}
EAPI Eina_List *
-evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
+evas_textblock_cursor_range_geometry_get(const Efl_Canvas_Text_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
{
Evas_Object_Textblock_Line *ln1, *ln2;
Evas_Object_Textblock_Item *it1, *it2;
@@ -11420,13 +11683,13 @@ evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, cons
if (cur1->obj != cur2->obj) return NULL;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur1->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur1->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur1->obj, MY_CLASS);
_relayout_if_needed(cur1->obj, o);
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
{
- const Evas_Textblock_Cursor *tc;
+ const Efl_Canvas_Text_Cursor *tc;
tc = cur1;
cur1 = cur2;
@@ -11494,7 +11757,7 @@ evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur,
if (!cur || !evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
- Evas_Textblock_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(cur->obj, MY_CLASS);
_relayout_if_needed(cur->obj, o);
@@ -11518,7 +11781,7 @@ EAPI Eina_Bool
evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur)
{
Eina_Bool ret = EINA_FALSE;
- Evas_Textblock_Cursor cur2;
+ Efl_Canvas_Text_Cursor cur2;
if (!cur) return EINA_FALSE;
Evas_Object_Protected_Data *obj = eo_data_scope_get(cur->obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -11534,14 +11797,16 @@ evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur)
}
/* general controls */
-EOLIAN static Eina_Bool
-_evas_textblock_line_number_geometry_get(const Eo *eo_obj, Evas_Textblock_Data *o, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
+EAPI Eina_Bool
+evas_object_textblock_line_number_geometry_get(const Eo *eo_obj, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
{
Evas_Object_Textblock_Line *ln;
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+
_relayout_if_needed((Evas_Object *)eo_obj, o);
ln = _find_layout_line_num(eo_obj, line);
@@ -11554,19 +11819,14 @@ _evas_textblock_line_number_geometry_get(const Eo *eo_obj, Evas_Textblock_Data *
}
static void
-_evas_object_textblock_clear_all(Evas_Object *eo_obj)
-{
- evas_obj_textblock_clear(eo_obj);
-}
-
-EOLIAN static void
-_evas_textblock_clear(Eo *eo_obj, Evas_Textblock_Data *o)
+_evas_object_textblock_clear(Evas_Object *eo_obj)
{
Eina_List *l;
- Evas_Textblock_Cursor *cur;
+ Efl_Canvas_Text_Cursor *cur;
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (o->paragraphs)
{
_paragraphs_free(eo_obj, o->paragraphs);
@@ -11589,7 +11849,7 @@ EAPI void
evas_object_textblock_clear(Evas_Object *eo_obj)
{
TB_HEAD();
- _evas_object_textblock_clear_all(eo_obj);
+ _evas_object_textblock_clear(eo_obj);
/* Force recreation of everything for textblock.
* FIXME: We have the same thing in other places, merge it... */
@@ -11598,7 +11858,7 @@ evas_object_textblock_clear(Evas_Object *eo_obj)
}
EOLIAN static void
-_evas_textblock_size_formatted_get(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Coord *w, Evas_Coord *h)
+_efl_canvas_text_size_formatted_get(Eo *eo_obj, Efl_Canvas_Text_Data *o, Evas_Coord *w, Evas_Coord *h)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -11748,7 +12008,7 @@ loop_advance:
/* FIXME: doc */
static void
_size_native_calc_paragraph_size(const Evas_Object *eo_obj,
- const Evas_Textblock_Data *o,
+ const Efl_Canvas_Text_Data *o,
Evas_Object_Textblock_Paragraph *par,
Textblock_Position *position,
Evas_Coord *_w, Evas_Coord *_h)
@@ -11837,7 +12097,7 @@ _size_native_calc_paragraph_size(const Evas_Object *eo_obj,
}
EOLIAN static void
-_evas_textblock_size_native_get(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Coord *w, Evas_Coord *h)
+_efl_canvas_text_size_native_get(Eo *eo_obj, Efl_Canvas_Text_Data *o, Evas_Coord *w, Evas_Coord *h)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -11871,7 +12131,7 @@ _evas_textblock_size_native_get(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Coord *
}
EOLIAN static void
-_evas_textblock_style_insets_get(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
+_efl_canvas_text_style_insets_get(Eo *eo_obj, Efl_Canvas_Text_Data *o, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
@@ -11884,7 +12144,7 @@ _evas_textblock_style_insets_get(Eo *eo_obj, Evas_Textblock_Data *o, Evas_Coord
}
EOLIAN static void
-_evas_textblock_eo_base_dbg_info_get(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNUSED, Eo_Dbg_Info *root)
+_efl_canvas_text_eo_base_dbg_info_get(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED, Eo_Dbg_Info *root)
{
eo_dbg_info_get(eo_super(eo_obj, MY_CLASS), root);
if (!root) return;
@@ -11896,9 +12156,9 @@ _evas_textblock_eo_base_dbg_info_get(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNU
char shorttext[48];
const Evas_Textblock_Style *ts = NULL;
- ts = evas_obj_textblock_style_get(eo_obj);
+ ts = evas_object_textblock_style_get(eo_obj);
style = evas_textblock_style_get(ts);
- text = evas_obj_textblock_text_markup_get(eo_obj);
+ text = evas_object_textblock_text_markup_get(eo_obj);
strncpy(shorttext, text, 38);
if (shorttext[37])
strcpy(shorttext + 37, "\xe2\x80\xa6"); /* HORIZONTAL ELLIPSIS */
@@ -11908,7 +12168,7 @@ _evas_textblock_eo_base_dbg_info_get(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNU
{
int w, h;
- evas_obj_textblock_size_formatted_get(eo_obj, &w, &h);
+ efl_canvas_text_size_formatted_get(eo_obj, &w, &h);
node = EO_DBG_INFO_LIST_APPEND(group, "Formatted size");
EO_DBG_INFO_APPEND(node, "w", EINA_VALUE_TYPE_INT, w);
EO_DBG_INFO_APPEND(node, "h", EINA_VALUE_TYPE_INT, h);
@@ -11916,7 +12176,7 @@ _evas_textblock_eo_base_dbg_info_get(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNU
{
int w, h;
- evas_obj_textblock_size_native_get(eo_obj, &w, &h);
+ efl_canvas_text_size_native_get(eo_obj, &w, &h);
node = EO_DBG_INFO_LIST_APPEND(group, "Native size");
EO_DBG_INFO_APPEND(node, "w", EINA_VALUE_TYPE_INT, w);
EO_DBG_INFO_APPEND(node, "h", EINA_VALUE_TYPE_INT, h);
@@ -11928,7 +12188,7 @@ static void
evas_object_textblock_init(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Evas_Textblock_Data *o;
+ Efl_Canvas_Text_Data *o;
static Eina_Bool linebreak_init = EINA_FALSE;
if (!linebreak_init)
@@ -11949,7 +12209,7 @@ evas_object_textblock_init(Evas_Object *eo_obj)
}
EOLIAN static void
-_evas_textblock_eo_base_destructor(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNUSED)
+_efl_canvas_text_eo_base_destructor(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED)
{
evas_object_textblock_free(eo_obj);
eo_destructor(eo_super(eo_obj, MY_CLASS));
@@ -11958,9 +12218,9 @@ _evas_textblock_eo_base_destructor(Eo *eo_obj, Evas_Textblock_Data *o EINA_UNUSE
static void
evas_object_textblock_free(Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
- _evas_object_textblock_clear_all(eo_obj);
+ _evas_object_textblock_clear(eo_obj);
evas_object_textblock_style_set(eo_obj, NULL);
while (evas_object_textblock_style_user_peek(eo_obj))
{
@@ -11969,9 +12229,9 @@ evas_object_textblock_free(Evas_Object *eo_obj)
free(o->cursor);
while (o->cursors)
{
- Evas_Textblock_Cursor *cur;
+ Efl_Canvas_Text_Cursor *cur;
- cur = (Evas_Textblock_Cursor *)o->cursors->data;
+ cur = (Efl_Canvas_Text_Cursor *)o->cursors->data;
o->cursors = eina_list_remove_list(o->cursors, o->cursors);
free(cur);
}
@@ -11990,6 +12250,12 @@ evas_object_textblock_free(Evas_Object *eo_obj)
_dicts_hyphen_detach(eo_obj);
}
#endif
+
+ /* free the style if exists */
+ if (o->current_style)
+ {
+ evas_textblock_style_free(o->current_style);
+ }
}
static void
@@ -12002,7 +12268,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Textblock_Paragraph *par, *start = NULL;
Evas_Object_Textblock_Item *itr;
Evas_Object_Textblock_Line *ln, *cur_ln = NULL;
- Evas_Textblock_Data *o = type_private_data;
+ Efl_Canvas_Text_Data *o = type_private_data;
Eina_List *shadows = NULL;
Eina_List *glows = NULL;
Eina_List *outlines = NULL;
@@ -12529,7 +12795,7 @@ evas_object_textblock_coords_recalc(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data)
{
- Evas_Textblock_Data *o = type_private_data;
+ Efl_Canvas_Text_Data *o = type_private_data;
#ifdef BIDI_SUPPORT
if (o->inherit_paragraph_direction)
@@ -12588,7 +12854,7 @@ evas_object_textblock_render_pre(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data)
{
- Evas_Textblock_Data *o = type_private_data;
+ Efl_Canvas_Text_Data *o = type_private_data;
int is_v, was_v;
/* dont pre-render the obj twice! */
@@ -12698,12 +12964,12 @@ evas_object_textblock_render_post(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj EINA_UNUSED,
void *type_private_data EINA_UNUSED)
{
- /* Evas_Textblock_Data *o; */
+ /* Efl_Canvas_Text_Data *o; */
/* this moves the current data to the previous state parts of the object */
/* in whatever way is safest for the object. also if we don't need object */
/* data anymore we can free it if the object deems this is a good idea */
-/* o = (Evas_Textblock_Data *)(obj->object_data); */
+/* o = (Efl_Canvas_Text_Data *)(obj->object_data); */
/* remove those pesky changes */
evas_object_clip_changes_clean(eo_obj);
/* move cur to prev safely for object data */
@@ -12713,21 +12979,21 @@ evas_object_textblock_render_post(Evas_Object *eo_obj,
static unsigned int evas_object_textblock_id_get(Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!o) return 0;
return MAGIC_OBJ_TEXTBLOCK;
}
static unsigned int evas_object_textblock_visual_id_get(Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!o) return 0;
return MAGIC_OBJ_CUSTOM;
}
static void *evas_object_textblock_engine_data_get(Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!o) return NULL;
return o->engine_data;
}
@@ -12757,7 +13023,7 @@ evas_object_textblock_scale_update(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj EINA_UNUSED,
void *type_private_data)
{
- Evas_Textblock_Data *o = type_private_data;
+ Efl_Canvas_Text_Data *o = type_private_data;
_evas_textblock_invalidate_all(o);
_evas_textblock_changed(o, eo_obj);
o->last_w = -1;
@@ -12768,7 +13034,7 @@ void
_evas_object_textblock_rehint(Evas_Object *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
Evas_Object_Textblock_Paragraph *par;
Evas_Object_Textblock_Line *ln;
@@ -12798,8 +13064,8 @@ _evas_object_textblock_rehint(Evas_Object *eo_obj)
}
EOLIAN static void
-_evas_textblock_evas_object_paragraph_direction_set(Eo *eo_obj,
- Evas_Textblock_Data *o,
+_efl_canvas_text_evas_object_paragraph_direction_set(Eo *eo_obj,
+ Efl_Canvas_Text_Data *o,
Evas_BiDi_Direction dir)
{
#ifdef BIDI_SUPPORT
@@ -12841,12 +13107,484 @@ _evas_textblock_evas_object_paragraph_direction_set(Eo *eo_obj,
}
EOLIAN static Evas_BiDi_Direction
-_evas_textblock_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED,
- Evas_Textblock_Data *o)
+_efl_canvas_text_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o)
{
return o->paragraph_direction;
}
+static int
+_prepend_text_run2(Efl_Canvas_Text_Cursor *cur, const char *s, const char *p)
+{
+ if ((s) && (p > s))
+ {
+ char *ts;
+
+ ts = alloca(p - s + 1);
+ strncpy(ts, s, p - s);
+ ts[p - s] = 0;
+ return _cursor_text_prepend(cur->obj, cur, ts, EINA_FALSE);
+ }
+ return 0;
+}
+
+EOLIAN static int
+_efl_canvas_text_cursor_text_append(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Canvas_Text_Cursor *cur,
+ const char *text)
+{
+
+ if (!text) return 0;
+
+ const char *off = text;
+ int len = 0;
+
+ /* We make use of prepending the cursor, but this needs to return the current
+ * position's cursor, so we use a temporary one. */
+ Evas_Textblock_Cursor *cur2 = evas_object_textblock_cursor_new (cur->obj);
+ evas_textblock_cursor_copy(cur, cur2); //cur --> cur2
+
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+
+ while (*off)
+ {
+ char *format = NULL;
+ int n = 1;
+ if (!strncmp(_PARAGRAPH_SEPARATOR_UTF8, off,
+ strlen(_PARAGRAPH_SEPARATOR_UTF8)))
+ {
+ format = "ps";
+ n = strlen(_PARAGRAPH_SEPARATOR_UTF8);
+ }
+ else if (!strncmp(_NEWLINE_UTF8, off, strlen(_NEWLINE_UTF8)))
+ {
+ format = "br";
+ n = strlen(_NEWLINE_UTF8);
+ }
+
+ if (format)
+ {
+ len += _prepend_text_run2(cur2, text, off);
+ if (evas_textblock_cursor_format_prepend(cur2, format))
+ {
+ len++;
+ }
+ text = off + n; /* sync text with next segment */
+ }
+ off += n;
+ }
+ len += _prepend_text_run2(cur2, text, off);
+ evas_textblock_cursor_free(cur2);
+ return len;
+}
+
+EOLIAN static void
+_efl_canvas_text_efl_text_text_set(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ const char *text)
+{
+ Evas_Textblock_Cursor *cur;
+
+ evas_object_textblock_text_markup_set(eo_obj, "");
+ cur = efl_canvas_text_cursor_new(eo_obj);
+ efl_canvas_text_cursor_text_append(eo_obj, cur, text);
+ evas_textblock_cursor_free(cur);
+}
+
+EOLIAN static const char *
+_efl_canvas_text_efl_text_text_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ evas_object_async_block(obj);
+
+ Evas_Object_Textblock_Node_Text *node;
+ char *utf8, *off;
+
+ struct
+ {
+ char *utf8;
+ int len;
+ } *en;
+ Eina_List *lst_utf8 = NULL;
+ Eina_List *i;
+
+ int len = 0;
+
+ //XXX: not efficient atm. This value will be cached properly so in the
+ // meantime the utf8 field will be cleared each call.
+ if (o->utf8)
+ {
+ free(o->utf8);
+ o->utf8 = NULL;
+ }
+
+ // XXX: won't use cursor_paragraph_text_get as it's inefficient
+ // for this function (gets ranges, uses strbuf).
+
+ // gets utf8s and calc length
+ EINA_INLIST_FOREACH(o->text_nodes, node)
+ {
+ en = malloc(sizeof(*en));
+ en->utf8 = eina_unicode_unicode_to_utf8(eina_ustrbuf_string_get(node->unicode), &en->len);
+ lst_utf8 = eina_list_append(lst_utf8, en);
+ len += en->len;
+ }
+
+ utf8 = malloc(len + 1); // with terminating '/0'
+ if (!utf8) goto end;
+
+ off = utf8;
+ EINA_LIST_FOREACH(lst_utf8, i, en)
+ {
+ memcpy(off, en->utf8, en->len);
+ off += en->len;
+ }
+ utf8[len] = '\0';
+ o->utf8 = utf8;
+
+end:
+ EINA_LIST_FREE(lst_utf8, en)
+ {
+ free(en);
+ }
+
+ return o->utf8;
+}
+
+/**
+ * @internal
+ * Returns the value of the current data of list node,
+ * and goes to the next list node.
+ *
+ * @param it the iterator.
+ * @param data the data of the current list node.
+ * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE.
+ */
+static Eina_Bool
+_evas_textblock_annotation_iterator_next(Efl_Canvas_Text_Annotation_Iterator *it, void **data)
+{
+ if (!it->current)
+ return EINA_FALSE;
+
+ *data = eina_list_data_get(it->current);
+ it->current = eina_list_next(it->current);
+
+ return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * Frees the annotation iterator.
+ * @param it the iterator to free
+ * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE.
+ */
+static Eina_Bool
+_evas_textblock_annotation_iterator_free(Efl_Canvas_Text_Annotation_Iterator *it)
+{
+ EINA_MAGIC_SET(&it->iterator, 0);
+ it->current = NULL;
+ eina_list_free(it->list);
+ free(it);
+ return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * Creates newly allocated iterator associated to a list.
+ * @param list The list.
+ * @return If the memory cannot be allocated, NULL is returned.
+ * Otherwise, a valid iterator is returned.
+ */
+Eina_Iterator *
+_evas_textblock_annotation_iterator_new(Eina_List *list)
+{
+ Evas_Textblock_Selection_Iterator *it;
+
+ it = calloc(1, sizeof(Efl_Canvas_Text_Annotation_Iterator));
+ if (!it) return NULL;
+
+ EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+ it->list = list;
+ it->current = list;
+
+ it->iterator.version = EINA_ITERATOR_VERSION;
+ it->iterator.next = FUNC_ITERATOR_NEXT(
+ _evas_textblock_annotation_iterator_next);
+ it->iterator.free = FUNC_ITERATOR_FREE(
+ _evas_textblock_annotation_iterator_free);
+
+ return &it->iterator;
+}
+
+static void
+_textblock_cursor_pos_at_fnode_set(Eo *eo_obj, Efl_Canvas_Text_Cursor *cur,
+ Evas_Object_Textblock_Node_Format *fnode)
+{
+ /* Get the relative offset to cur's text node */
+ size_t off = _evas_textblock_node_format_pos_get(fnode);
+ efl_canvas_text_cursor_pos_set(eo_obj, cur, off);
+}
+
+static Eina_Bool
+_textblock_annotation_set(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Annotation *an,
+ Efl_Canvas_Text_Cursor *start, Efl_Canvas_Text_Cursor *end,
+ const char *format, Eina_Bool is_item)
+{
+ int len;
+ char *buf;
+ Evas_Textblock_Node_Format *fnode;
+
+ if (an->is_item)
+ {
+ ERR("Cannot reset format of \"item\" annotations. This is a special"
+ "annotation that should not be modified using this function");
+ return EINA_FALSE;
+ }
+
+ /* Add opening format at 'start' */
+ len = strlen(format);
+ buf = malloc(len + 3);
+ sprintf(buf, "<%s>", format);
+ _evas_textblock_cursor_format_append(start, buf, &fnode, is_item);
+ free(buf);
+ an->start_node = fnode;
+ fnode->annotation = an;
+
+ /* Add a closing format at end (i.e. format does not apply at end) */
+ len = strlen(format);
+ buf = malloc(len + 4);
+ sprintf(buf, "</%s>", format);
+ if (is_item) evas_textblock_cursor_char_next(end);
+ _evas_textblock_cursor_format_append(end, buf, &fnode, is_item);
+ free(buf);
+ an->end_node = fnode;
+ fnode->annotation = an;
+
+ o->format_changed = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+EOLIAN static const char *
+_efl_canvas_text_annotation_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ Efl_Canvas_Text_Annotation *annotation)
+{
+ if (!annotation || (annotation->obj != eo_obj))
+ {
+ ERR("Used invalid handle or of a different object");
+ return NULL;
+ }
+
+ return (annotation->start_node ? annotation->start_node->format : NULL);
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_annotation_set(Eo *eo_obj,
+ Efl_Canvas_Text_Data *o, Efl_Canvas_Text_Annotation *annotation,
+ const char *format)
+{
+ Efl_Canvas_Text_Cursor *start, *end;
+ Eina_Bool ret = EINA_TRUE;
+
+ if (!annotation || (annotation->obj != eo_obj))
+ {
+ ERR("Used invalid handle or of a different object");
+ return EINA_FALSE;
+ }
+
+ if (!annotation->start_node || !annotation->end_node) return EINA_FALSE;
+ if (!format || (format[0] == '\0')) return EINA_FALSE;
+
+ start = efl_canvas_text_cursor_new(eo_obj);
+ end = efl_canvas_text_cursor_new(eo_obj);
+
+ /* XXX: Not efficient but works and saves code */
+ _textblock_cursor_pos_at_fnode_set(eo_obj, start, annotation->start_node);
+ _textblock_cursor_pos_at_fnode_set(eo_obj, end, annotation->end_node);
+
+ _evas_textblock_node_format_remove(o, annotation->start_node, 0);
+ _evas_textblock_node_format_remove(o, annotation->end_node, 0);
+
+ if (!_textblock_annotation_set(eo_obj, o, annotation, start, end, format,
+ EINA_FALSE))
+ {
+ ret = EINA_FALSE;
+ }
+
+ return ret;
+}
+
+static void
+_evas_textblock_annotation_remove(Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Annotation *an, Eina_Bool remove_nodes)
+{
+ if (remove_nodes)
+ {
+ if (an->is_item)
+ {
+ /* Remove the OBJ character along with the cursor. */
+ Efl_Canvas_Text_Cursor *cur = efl_canvas_text_cursor_new(an->obj);
+ _textblock_cursor_pos_at_fnode_set(an->obj, cur, an->start_node);
+ evas_textblock_cursor_char_delete(cur);
+ evas_textblock_cursor_free(cur);
+ return; // 'an' should be deleted after char deletion.
+ }
+ _evas_textblock_node_format_remove(o, an->start_node, 0);
+ _evas_textblock_node_format_remove(o, an->end_node, 0);
+ }
+ o->annotations = (Efl_Canvas_Text_Annotation *)
+ eina_inlist_remove(EINA_INLIST_GET(o->annotations),
+ EINA_INLIST_GET(an));
+ free(an);
+}
+
+static void
+_evas_textblock_annotations_clear(Efl_Canvas_Text_Data *o)
+{
+ Efl_Canvas_Text_Annotation *an;
+
+ EINA_INLIST_FREE(o->annotations, an)
+ {
+ _evas_textblock_annotation_remove(o, an, EINA_TRUE);
+ }
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_annotation_del(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o, Efl_Canvas_Text_Annotation *annotation)
+{
+ if (!annotation || (annotation->obj != eo_obj))
+ {
+ ERR("Used invalid handle or of a different object");
+ return EINA_FALSE;
+ }
+
+ _evas_textblock_annotation_remove(o, annotation, EINA_TRUE);
+ o->format_changed = EINA_TRUE;
+
+ //XXX: It's a workaround. The underlying problem is that only new format
+ // nodes are checks when their respective text nodes are invalidated (see
+ // _format_changes_invalidate_text_nodes). Complete removal of the format
+ // nodes was not handled properly (as formats could only be removed via
+ // text changes e.g. deleting characters).
+ _evas_textblock_invalidate_all(o);
+
+ _evas_textblock_changed(o, eo_obj);
+ return EINA_TRUE;
+}
+
+static Efl_Canvas_Text_Annotation *
+_textblock_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Cursor *start, Efl_Canvas_Text_Cursor *end,
+ const char *format, Eina_Bool is_item)
+{
+ Efl_Canvas_Text_Annotation *ret = NULL;
+ Eina_Strbuf *buf;
+ Eina_Bool first = EINA_TRUE;
+ const char *item;
+
+ if (!format || (format[0] == '\0') ||
+ efl_canvas_text_cursor_compare(eo_obj, start, end) > 0)
+ {
+ return NULL;
+ }
+
+ /* Sanitize the string and reject format items, closing '/' marks. */
+ buf = eina_strbuf_new();
+ while ((item = _format_parse(&format)))
+ {
+ int itlen = format - item;
+ /* We care about all of the formats even after a - except for
+ * item which we don't care after a - because it's just a standard
+ * closing */
+ if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) ||
+ (!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) ||
+ (!strncmp(item, "br", itlen) && (itlen >= 2)) ||
+ (!strncmp(item, "tab", itlen) && (itlen >= 3)) ||
+ (!strncmp(item, "ps", itlen) && (itlen >= 2)) ||
+ (!strncmp(item, "item", itlen) && (itlen >= 4)))
+ {
+ continue;
+ }
+ if (first)
+ {
+ first = EINA_FALSE;
+ }
+ else
+ {
+ eina_strbuf_append_length(buf, " ", 1);
+ }
+ eina_strbuf_append_length(buf, item, itlen);
+ }
+
+ format = eina_strbuf_string_steal(buf);
+ if (!format || (format[0] == '\0'))
+ {
+ return NULL;
+ }
+
+ ret = calloc(1, sizeof(Efl_Canvas_Text_Annotation));
+ ret->obj = eo_obj;
+
+ o->annotations = (Efl_Canvas_Text_Annotation *)
+ eina_inlist_append(EINA_INLIST_GET(o->annotations),
+ EINA_INLIST_GET(ret));
+
+ _textblock_annotation_set(eo_obj, o, ret, start, end, format, is_item);
+ ret->is_item = is_item;
+
+ _evas_textblock_changed(o, eo_obj);
+
+ return ret;
+}
+
+EOLIAN static Efl_Canvas_Text_Annotation *
+_efl_canvas_text_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o,
+ Efl_Canvas_Text_Cursor *start, Efl_Canvas_Text_Cursor *end,
+ const char *format)
+{
+ return _textblock_annotation_insert(eo_obj, o, start, end, format,
+ EINA_FALSE);
+}
+
+EOLIAN static Eina_Iterator *
+_efl_canvas_text_annotation_in_range_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o EINA_UNUSED,
+ const Evas_Textblock_Cursor *start, const Evas_Textblock_Cursor *end)
+{
+ Eina_List *lst = NULL;
+ Efl_Canvas_Text_Annotation *it;
+
+ EINA_INLIST_FOREACH(o->annotations, it)
+ {
+ Efl_Canvas_Text_Cursor *start2, *end2;
+ start2 = efl_canvas_text_cursor_new(eo_obj);
+ end2 = efl_canvas_text_cursor_new(eo_obj);
+ if (!it->start_node || !it->end_node) continue;
+ _textblock_cursor_pos_at_fnode_set(eo_obj, start2, it->start_node);
+ _textblock_cursor_pos_at_fnode_set(eo_obj, end2, it->end_node);
+ evas_textblock_cursor_char_prev(end2);
+ if (!((efl_canvas_text_cursor_compare(eo_obj, start2, end) > 0) ||
+ (efl_canvas_text_cursor_compare(eo_obj, end2, start) < 0)))
+ {
+ lst = eina_list_append(lst, it);
+ }
+ }
+ return _evas_textblock_annotation_iterator_new(lst);
+}
+
+EOLIAN static Efl_Canvas_Text_Annotation *
+_efl_canvas_text_object_item_insert(Eo *eo_obj EINA_UNUSED,
+ Efl_Canvas_Text_Data *o EINA_UNUSED,
+ Efl_Canvas_Text_Cursor *cur, const char *format)
+{
+ Efl_Canvas_Text_Annotation *ret;
+ Efl_Canvas_Text_Cursor *cur2 = efl_canvas_text_cursor_new(eo_obj);
+ evas_textblock_cursor_copy(cur, cur2);
+ ret = _textblock_annotation_insert(eo_obj, o, cur, cur2, format, EINA_TRUE);
+ efl_canvas_text_cursor_free(eo_obj, cur2);
+ return ret;
+}
+
/**
* @}
*/
@@ -12856,7 +13594,7 @@ _evas_textblock_evas_object_paragraph_direction_get(Eo *eo_obj EINA_UNUSED,
EAPI Eina_Bool
_evas_textblock_check_item_node_link(Evas_Object *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
Evas_Object_Textblock_Paragraph *par;
Evas_Object_Textblock_Line *ln;
Evas_Object_Textblock_Item *it;
@@ -12953,4 +13691,4 @@ ppar(Evas_Object_Textblock_Paragraph *par)
#endif
-#include "canvas/evas_textblock.eo.c"
+#include "canvas/efl_canvas_text.eo.c"
diff --git a/src/lib/evas/canvas/evas_textblock.eo b/src/lib/evas/canvas/evas_textblock.eo
deleted file mode 100644
index 1de4638138..0000000000
--- a/src/lib/evas/canvas/evas_textblock.eo
+++ /dev/null
@@ -1,331 +0,0 @@
-struct @extern Evas.Textblock.Cursor;
-struct @extern Evas.Textblock.Style;
-struct Evas.Textblock.Node_Format;
-
-class Evas.Textblock (Evas.Object)
-{
- legacy_prefix: evas_object_textblock;
- eo_prefix: evas_obj_textblock;
- methods {
- @property text_markup {
- set {
- [[Sets the tetxblock's text to the markup text.
-
- Note: assumes text does not include the unicode object
- replacement char (0xFFFC)
- ]]
- }
- get {
- [[Get the markup of the object.]]
- }
- values {
- text: string; [[The markup text to use.]]
- }
- }
- @property valign {
- set {
- [[Sets the vertical alignment of text within the textblock object
- as a whole.
-
- Normally alignment is 0.0 (top of object). Values given should
- be between 0.0 and 1.0 (1.0 bottom of object, 0.5 being
- vertically centered etc.).
-
- @since 1.1
- ]]
- }
- get {
- [[Gets the vertical alignment of a textblock
-
- @since 1.1
- ]]
- }
- values {
- align: double; [[The alignment set for the object.]]
- }
- }
- @property bidi_delimiters {
- set {
- [[Sets the BiDi delimiters used in the textblock.
-
- BiDi delimiters are use for in-paragraph separation of bidi
- segments. This is useful for example in recipients fields of
- e-mail clients where bidi oddities can occur when mixing RTL
- and LTR.
-
- @since 1.1
- ]]
- }
- get {
- [[Gets the BiDi delimiters used in the textblock.
-
- BiDi delimiters are use for in-paragraph separation of bidi
- segments. This is useful for example in recipients fields of
- e-mail clients where bidi oddities can occur when mixing RTL
- and LTR.
-
- @since 1.1
- ]]
- }
- values {
- delim: string; [[A null terminated string of delimiters, e.g ",|" or $null if empty.]]
- }
- }
- @property replace_char {
- set {
- [[Set the "replacement character" to use for the given textblock object.]]
- }
- values {
- ch: string; [[The charset name.]]
- }
- }
- @property legacy_newline {
- set {
- [[Sets newline mode. When true, newline character will behave
- as a paragraph separator.
-
- @since 1.1
- ]]
- }
- get {
- [[Gets newline mode. When true, newline character behaves
- as a paragraph separator.
-
- @since 1.1
- ]]
- }
- values {
- mode: bool; [[$true for legacy mode, $false otherwise.]]
- }
- }
- @property style {
- set {
- [[Set the objects style to $ts.]]
- }
- get {
- [[Get the style of an object.]]
- }
- values {
- ts: const(Evas.Textblock.Style)*; [[The style.]]
- }
- }
- @property node_format_first {
- get {
- [[Gets the first format node.]]
- legacy: evas_textblock_node_format_first_get;
- }
- values {
- format: const(Evas.Textblock.Node_Format)*;
- }
- }
- @property size_formatted {
- get {
- [[Get the formatted width and height.
-
- This calculates the actual size after restricting the
- textblock to the current size of the object.
-
- The main difference between this and @.size_native.get
- is that the "native" function does not wrapping into account
- it just calculates the real width of the object if it was
- placed on an infinite canvas, while this function gives the
- size after wrapping according to the size restrictions of the
- object.
-
- For example for a textblock containing the text:
- "You shall not pass!" with no margins or padding and assuming
- a monospace font and a size of 7x10 char widths (for simplicity)
- has a native size of 19x1 and a formatted size of 5x4.
- ]]
- }
- values {
- w: Evas.Coord; [[The width of the object.]]
- h: Evas.Coord; [[The height of the object.]]
- }
- }
- @property node_format_last {
- get {
- [[Gets the last format node.]]
- legacy: evas_textblock_node_format_last_get;
- }
- values {
- format: const(Evas.Textblock.Node_Format)*;
- }
- }
- @property cursor {
- get {
- [[Get the object's main cursor.]]
- return: Evas.Textblock.Cursor *;
- }
- }
- @property size_native {
- get {
- [[Get the native width and height.
-
- This calculates the actual size without taking account the
- current size of the object.
-
- The main difference between this and @.size_formatted.get
- is that the "native" function does not take wrapping into
- account it just calculates the real width of the object if
- it was placed on an infinite canvas, while the "formatted"
- function gives the size after wrapping text according to
- the size restrictions of the object.
-
- For example for a textblock containing the text:
- "You shall not pass!" with no margins or padding and assuming
- a monospace font and a size of 7x10 char widths (for simplicity)
- has a native size of 19x1 and a formatted size of 5x4.
- ]]
- }
- values {
- w: Evas.Coord; [[The width returned.]]
- h: Evas.Coord; [[The height returned.]]
- }
- }
- @property style_insets {
- get {}
- values {
- l: Evas.Coord;
- r: Evas.Coord;
- t: Evas.Coord;
- b: Evas.Coord;
- }
- }
- line_number_geometry_get @const {
- [[Get the geometry of a line number.]]
- return: bool; [[$true on success, $false otherwise.]]
- params {
- @in line: int; [[The line number.]]
- @out cx: Evas.Coord; [[x coord of the line.]]
- @out cy: Evas.Coord; [[y coord of the line.]]
- @out cw: Evas.Coord; [[w coord of the line.]]
- @out ch: Evas.Coord; [[h coord of the line.]]
- }
- }
- replace_char_get {
- [[Get the "replacement character" for given textblock object.
-
- Returns $null if no replacement character is in use.
- ]]
- return: string; [[Replacement character or $null.]]
- }
- style_user_pop {
- [[Del the from the top of the user style stack.
-
- See also @.style.get.
-
- @since 1.2
- ]]
- }
- cursor_new @const {
- [[Create a new cursor, associate it to the obj and init it to point
- to the start of the textblock.
-
- Association to the object means the cursor will be updated when
- the object will change.
-
- Note: if you need speed and you know what you are doing, it's
- slightly faster to just allocate the cursor yourself and not
- associate it. (only people developing the actual object, and
- not users of the object).
- ]]
- return: Evas.Textblock.Cursor *; [[The new cursor.]]
- }
- node_format_list_get @const {
- legacy: evas_textblock_node_format_list_get;
- return: const(list<Evas.Object>);
- params {
- @in anchor: string;
- }
- }
- style_user_peek @const {
- [[Get (don't remove) the style at the top of the user style stack.
-
- See also @.style.get.
-
- @since 1.2
- ]]
- return: const(Evas.Textblock.Style)*; [[The style of the object.]]
- }
- node_format_remove_pair {
- [[Remove a format node and its match.]]
- legacy: evas_textblock_node_format_remove_pair;
- params {
- @in n: Evas.Textblock.Node_Format *;
- }
- }
- clear {
- [[Clear the textblock object.
-
- Note: Does *NOT* free the Evas object itself.
- ]]
- legacy: null;
- }
- style_user_push {
- [[Push ts to the top of the user style stack.
-
- FIXME: API is solid but currently only supports 1 style in the
- stack.
-
- The user style overrides the corresponding elements of the
- regular style. This is the proper way to do theme overrides
- in code.
-
- See also @.style.set.
-
- @since 1.2
- ]]
- params {
- @in ts: Evas.Textblock.Style *; [[The style to set.]]
- }
- }
- obstacle_add {
- [[Add obstacle evas object $eo_obs to be observed during layout
- of text.
-
- The textblock does the layout of the text according to the
- position of the obstacle.
-
- @since 1.15
- ]]
- params {
- @in eo_obs: Evas.Object;
- }
- return: bool; [[$true on success, $false otherwise.]]
- }
- obstacle_del {
- [[Removes $eo_obs from observation during text layout.
-
- @since 1.15
- ]]
- params {
- @in eo_obs: Evas.Object;
- }
- return: bool; [[$true on success, $false otherwise.]]
- }
- obstacles_update {
- [[Triggers for relayout due to obstacles' state change.
-
- The obstacles alone don't affect the layout, until this is
- called. Use this after doing changes (moving, positioning etc.)
- in the obstacles that you would like to be considered in the
- layout.
-
- For example: if you have just repositioned the obstacles to
- differrent coordinates relative to the textblock, you need to
- call this so it will consider this new state and will relayout
- the text.
-
- @since 1.15
- ]]
- }
- }
- implements {
- Eo.Base.constructor;
- Eo.Base.destructor;
- Eo.Base.dbg_info_get;
- Evas.Object.paragraph_direction.set;
- Evas.Object.paragraph_direction.get;
- }
-}
diff --git a/src/lib/evas/canvas/evas_textblock_hyphenation.x b/src/lib/evas/canvas/evas_textblock_hyphenation.x
index 9c5f47c2fa..bdcf37f92c 100644
--- a/src/lib/evas/canvas/evas_textblock_hyphenation.x
+++ b/src/lib/evas/canvas/evas_textblock_hyphenation.x
@@ -17,7 +17,7 @@ static size_t _hyphen_clients = 0;
static void
_dicts_hyphen_init(Eo *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!o->hyphenating)
{
@@ -93,7 +93,7 @@ _dicts_hyphen_free(void)
static inline void
_dicts_hyphen_detach(Eo *eo_obj)
{
- Evas_Textblock_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+ Efl_Canvas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
if (!o->hyphenating) return;
o->hyphenating = EINA_FALSE;
diff --git a/src/tests/evas/evas_test_textblock.c b/src/tests/evas/evas_test_textblock.c
index 9120b228da..94a0f86a3a 100644
--- a/src/tests/evas/evas_test_textblock.c
+++ b/src/tests/evas/evas_test_textblock.c
@@ -964,9 +964,8 @@ START_TEST(evas_textblock_split_cursor)
/* Logical cursor after "test " */
evas_textblock_cursor_pos_set(cur, 6);
- fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL,
- NULL, &cx2, NULL, NULL, NULL,
- EVAS_TEXTBLOCK_CURSOR_BEFORE));
+ fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, NULL,
+ &cx2, NULL, NULL, NULL, EVAS_TEXTBLOCK_CURSOR_BEFORE));
evas_textblock_cursor_pos_set(cur, 18);
evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL);
evas_textblock_cursor_pos_set(cur, 20);
@@ -976,9 +975,8 @@ START_TEST(evas_textblock_split_cursor)
/* Logical cursor before "a" */
evas_textblock_cursor_pos_set(cur, 11);
- fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL,
- NULL, &cx2, NULL, NULL, NULL,
- EVAS_TEXTBLOCK_CURSOR_BEFORE));
+ fail_if(!evas_textblock_cursor_geometry_bidi_get(cur, &cx, NULL, NULL, NULL,
+ &cx2, NULL, NULL, NULL, EVAS_TEXTBLOCK_CURSOR_BEFORE));
evas_textblock_cursor_pos_set(cur, 11);
evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL);
evas_textblock_cursor_pos_set(cur, 10);
@@ -3973,6 +3971,391 @@ START_TEST(evas_textblock_hyphenation)
END_TEST;
#endif
+START_TEST(evas_textblock_text_iface)
+{
+ START_TB_TEST();
+ Evas_Coord nw, nh;
+ Evas_Coord bw, bh;
+ Evas_Coord w, h;
+ const char *utf8;
+
+ /* Set text */
+ efl_text_set(tb, "hello world");
+ evas_object_textblock_size_native_get(tb, &bw, &bh);
+ efl_text_set(tb, "hello\nworld");
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_gt(nh, bh);
+ ck_assert_int_gt(bw, nw);
+ efl_text_set(tb, "hello\nworld\ngoodbye\nworld");
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_ge(nh, bh * 3);
+
+ /* Delete text */
+ efl_text_set(tb, "a");
+ evas_object_textblock_size_native_get(tb, &bw, &bh);
+ efl_text_set(tb, "a\nb");
+ efl_canvas_text_cursor_pos_set(tb, cur, 1);
+ efl_canvas_text_cursor_char_delete(tb, cur);
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_eq(nh, bh);
+
+ /* Paragraph checks */
+ efl_text_set(tb, "d");
+ evas_object_textblock_size_native_get(tb, &w, &h);
+ efl_text_set(tb, "aa\nb\nc\nd");
+ evas_object_textblock_size_native_get(tb, &bw, &bh);
+ efl_canvas_text_cursor_pos_set(tb, cur, 0);
+ efl_canvas_text_cursor_char_delete(tb, cur); // delete 'a'
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_eq(nh, bh);
+ efl_canvas_text_cursor_char_delete(tb, cur); // delete 'a'
+ efl_canvas_text_cursor_char_delete(tb, cur); // delete '\n'
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_lt(nh, bh);
+ /* "b\nc\nd" is left */
+ efl_canvas_text_cursor_char_delete(tb, cur); // b
+ efl_canvas_text_cursor_char_delete(tb, cur); // \n
+ efl_canvas_text_cursor_char_delete(tb, cur); // c
+ efl_canvas_text_cursor_char_delete(tb, cur); // \n
+ /* expecting "d" only */
+ evas_object_textblock_size_native_get(tb, &nw, &nh);
+ ck_assert_int_eq(nh, h);
+ ck_assert_int_eq(nw, w);
+
+ /* Text get */
+ utf8 = "a";
+ efl_text_set(tb, utf8);
+ ck_assert_str_eq(utf8, efl_text_get(tb));
+ utf8 = "a\nb";
+ efl_text_set(tb, utf8);
+ ck_assert_str_eq(utf8, efl_text_get(tb));
+ utf8 = "a\u2029b";
+ efl_text_set(tb, utf8);
+ ck_assert_str_eq(utf8, efl_text_get(tb));
+ utf8 = "a\u2029bc\ndef\n\u2029";
+ efl_text_set(tb, utf8);
+ ck_assert_str_eq(utf8, efl_text_get(tb));
+ utf8 = "\u2029\n\n\n\n\u2029\n\u2029\n\n\n";
+ efl_text_set(tb, utf8);
+ ck_assert_str_eq(utf8, efl_text_get(tb));
+
+ END_TB_TEST();
+}
+END_TEST;
+
+static void
+_test_check_annotation(Evas_Object *tb,
+ size_t start_pos, size_t end_pos,
+ size_t len, const char **formats)
+{
+ Efl_Canvas_Text_Annotation *an;
+ Efl_Canvas_Text_Cursor *start, *end;
+
+ start = efl_canvas_text_cursor_new(tb);
+ end = efl_canvas_text_cursor_new(tb);
+
+ efl_canvas_text_cursor_pos_set(tb, start, start_pos);
+ efl_canvas_text_cursor_pos_set(tb, end, end_pos);
+
+ Eina_Iterator *it =
+ efl_canvas_text_annotation_in_range_get(tb, start, end);
+
+ efl_canvas_text_cursor_free(tb, start);
+ efl_canvas_text_cursor_free(tb, end);
+
+ size_t i = 0;
+ EINA_ITERATOR_FOREACH(it, an)
+ {
+ const char *fmt = efl_canvas_text_annotation_get(tb,
+ an);
+ ck_assert_msg((i < len),
+ "No formats to check but current annotation is: %s\n", fmt);
+ ck_assert_str_eq(fmt, *formats);
+ formats++;
+ i++;
+ }
+ ck_assert_msg((i == len),
+ "Expected next format (index %lu): %s, but reached end of annotations\n",
+ i, *formats);
+
+ eina_iterator_free(it);
+}
+
+#define _COMP_STR(...) ((const char *[]) { __VA_ARGS__ })
+#define _CREATE_PARAMS(X) (sizeof(X) / sizeof(X[0])), (X)
+#define _COMP_PARAMS(...) _CREATE_PARAMS(_COMP_STR(__VA_ARGS__))
+
+START_TEST(evas_textblock_annotation)
+{
+ START_TB_TEST();
+ Efl_Canvas_Text_Annotation *an, *an2;
+ Efl_Canvas_Text_Cursor *start, *end;
+
+ start = efl_canvas_text_cursor_new(tb);
+ end = efl_canvas_text_cursor_new(tb);
+
+ const char *buf =
+ "This text will check annotation."
+ " By \"annotating\" the text, we can apply formatting simply by"
+ " specifying a range (start, end) in the text, and the format we want"
+ " for it."
+ ;
+
+ efl_text_set(tb, buf);
+
+ /* Check some trivial cases */
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 3);
+ ck_assert(!efl_canvas_text_annotation_insert(tb, start, end, NULL));
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 3);
+ ck_assert(!efl_canvas_text_annotation_insert(tb, start, end, ""));
+ efl_canvas_text_cursor_pos_set(tb, start, 1);
+ efl_canvas_text_cursor_pos_set(tb, end, 0);
+ ck_assert(!efl_canvas_text_annotation_insert(tb, start, end, "color=#fff"));
+
+ /* Insert and check correct positions */
+ _test_check_annotation(tb, 0, 10, _COMP_PARAMS());
+
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 3);
+ efl_canvas_text_annotation_insert(tb, start, end, "font_weight=bold");
+ _test_check_annotation(tb, 0, 2, _COMP_PARAMS("font_weight=bold"));
+ _test_check_annotation(tb, 0, 2, _COMP_PARAMS("font_weight=bold"));
+ _test_check_annotation(tb, 4, 10, _COMP_PARAMS());
+
+ efl_canvas_text_cursor_pos_set(tb, start, 50);
+ efl_canvas_text_cursor_pos_set(tb, end, 60);
+ efl_canvas_text_annotation_insert(tb, start, end, "color=#0ff");
+ _test_check_annotation(tb, 0, 49, _COMP_PARAMS("font_weight=bold"));
+ _test_check_annotation(tb, 0, 50, _COMP_PARAMS("font_weight=bold", "color=#0ff"));
+ _test_check_annotation(tb, 0, 55, _COMP_PARAMS("font_weight=bold", "color=#0ff"));
+ _test_check_annotation(tb, 0, 59, _COMP_PARAMS("font_weight=bold", "color=#0ff"));
+ _test_check_annotation(tb, 40, 50, _COMP_PARAMS("color=#0ff"));
+ _test_check_annotation(tb, 40, 51, _COMP_PARAMS("color=#0ff"));
+ _test_check_annotation(tb, 40, 61, _COMP_PARAMS("color=#0ff"));
+ _test_check_annotation(tb, 59, 60, _COMP_PARAMS("color=#0ff"));
+ _test_check_annotation(tb, 60, 61, _COMP_PARAMS());
+
+ /* See that annotation's positions are updated as text is inserted */
+ efl_text_set(tb, "hello");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 2);
+ an = efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ _test_check_annotation(tb, 2, 3, _COMP_PARAMS());
+ evas_textblock_cursor_pos_set(cur, 0);
+ evas_textblock_cursor_text_append(cur, "a");
+ _test_check_annotation(tb, 2, 3, _COMP_PARAMS("color=#fff"));
+ _test_check_annotation(tb, 3, 4, _COMP_PARAMS());
+
+ /* Replace annotations's format */
+ efl_canvas_text_annotation_set(tb, an, "font_size=14");
+ _test_check_annotation(tb, 2, 3, _COMP_PARAMS("font_size=14"));
+ _test_check_annotation(tb, 3, 4, _COMP_PARAMS());
+
+ efl_text_set(tb, "hello world");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 2);
+ an = efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ efl_canvas_text_cursor_pos_set(tb, start, 2);
+ efl_canvas_text_cursor_pos_set(tb, end, 3);
+ an2 = efl_canvas_text_annotation_insert(tb, start, end, "font_size=14");
+ _test_check_annotation(tb, 0, 1, _COMP_PARAMS("color=#fff"));
+ _test_check_annotation(tb, 2, 3, _COMP_PARAMS("font_size=14"));
+ _test_check_annotation(tb, 0, 3, _COMP_PARAMS("color=#fff", "font_size=14"));
+ efl_canvas_text_annotation_set(tb, an, "font_size=10");
+ efl_canvas_text_annotation_set(tb, an2, "color=#000");
+ _test_check_annotation(tb, 2, 3, _COMP_PARAMS("color=#000"));
+ _test_check_annotation(tb, 0, 1, _COMP_PARAMS("font_size=10"));
+ _test_check_annotation(tb, 0, 3, _COMP_PARAMS("font_size=10", "color=#000"));
+
+ /* Delete annotations directly */
+ efl_text_set(tb, "hello world");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 2);
+ an = efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ efl_canvas_text_cursor_pos_set(tb, start, 3);
+ efl_canvas_text_cursor_pos_set(tb, end, 4);
+ an2 = efl_canvas_text_annotation_insert(tb, start, end, "font_size=14");
+ efl_canvas_text_annotation_del(tb, an);
+ _test_check_annotation(tb, 0, 3, _COMP_PARAMS("font_size=14"));
+ efl_canvas_text_annotation_del(tb, an2);
+ _test_check_annotation(tb, 0, 3, _COMP_PARAMS());
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 1);
+ an = efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ _test_check_annotation(tb, 1, 3, _COMP_PARAMS());
+ _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff"));
+ efl_canvas_text_annotation_del(tb, an);
+ _test_check_annotation(tb, 0, 0, _COMP_PARAMS());
+
+ /* Check blocking of "item formats" */
+ efl_text_set(tb, "hello world");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 1);
+ efl_canvas_text_annotation_insert(tb, start, end, "ps");
+ _test_check_annotation(tb, 0, 1, _COMP_PARAMS());
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 1);
+ efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ _test_check_annotation(tb, 0, 1, _COMP_PARAMS("color=#fff"));
+ efl_canvas_text_cursor_pos_set(tb, start, 2);
+ efl_canvas_text_cursor_pos_set(tb, end, 3);
+ efl_canvas_text_annotation_insert(tb, start, end, "br");
+ efl_canvas_text_cursor_pos_set(tb, start, 6);
+ efl_canvas_text_cursor_pos_set(tb, end, 7);
+ efl_canvas_text_annotation_insert(tb, start, end, "item");
+ _test_check_annotation(tb, 0, 8, _COMP_PARAMS("color=#fff"));
+
+ /* Check "item" annotations */
+ efl_text_set(tb, "abcd");
+ efl_canvas_text_cursor_pos_set(tb, cur, 4);
+ an = efl_canvas_text_object_item_insert(tb, cur, "size=16x16");
+ _test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16"));
+
+ /* Check that format is not extended if it's an "object item" */
+ evas_textblock_cursor_pos_set(cur, 5);
+ evas_textblock_cursor_text_append(cur, "a");
+ _test_check_annotation(tb, 5, 7, _COMP_PARAMS());
+ _test_check_annotation(tb, 0, 3, _COMP_PARAMS());
+
+ /* Remove annotation of "item" also removes the OBJ character */
+ {
+ int blen, len;
+ evas_textblock_cursor_pos_set(cur, 5);
+ blen = evas_textblock_cursor_paragraph_text_length_get(cur);
+ efl_canvas_text_annotation_del(tb, an);
+ len = evas_textblock_cursor_paragraph_text_length_get(cur);
+ ck_assert_int_eq(len, blen - 1);
+ _test_check_annotation(tb, 0, 5, _COMP_PARAMS());
+ }
+
+ /* Using annotations with new text API */
+ efl_text_set(tb, "hello");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 5);
+ efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ _test_check_annotation(tb, 3, 3, _COMP_PARAMS("color=#fff"));
+ evas_textblock_cursor_pos_set(cur, 5);
+ /* Old API */
+ evas_textblock_cursor_text_append(cur, "a");
+ _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff"));
+ _test_check_annotation(tb, 5, 5, _COMP_PARAMS());
+ /* New API */
+ efl_canvas_text_cursor_text_append(tb, cur, "a");
+ _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff"));
+ _test_check_annotation(tb, 5, 5, _COMP_PARAMS("color=#fff"));
+
+ /* Specific case with PS */
+ efl_text_set(tb, "hello\nworld");
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 5);
+ efl_canvas_text_annotation_insert(tb, start, end, "color=#fff");
+ _test_check_annotation(tb, 4, 4, _COMP_PARAMS("color=#fff"));
+ evas_textblock_cursor_pos_set(cur, 5);
+ /* Cursor position is now: hello|\nworld */
+ efl_canvas_text_cursor_text_append(tb, cur, "a");
+ _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff"));
+ _test_check_annotation(tb, 5, 5, _COMP_PARAMS("color=#fff"));
+
+ END_TB_TEST();
+}
+END_TEST;
+
+START_TEST(efl_canvas_text_style)
+{
+ START_TB_TEST();
+
+ Efl_Canvas_Text_Cursor *start, *end;
+
+ Evas_Coord w;
+ Evas_Coord bw;
+ const char *buf;
+
+ buf =
+ "DEFAULT='font=Sans font_size=12 color=#fff wrap=word text_class=entry'"
+ "br='\n'"
+ "ps='ps'"
+ "tab='\t'";
+
+ efl_canvas_text_style_set(tb, buf);
+ ck_assert_str_eq(efl_canvas_text_style_get(tb), buf);
+
+ buf =
+ "DEFAULT='font=Sans font_size=12 color=#fff'"
+ "c='color=#000'"
+ "ps='br'"
+ "tab='\t'";
+
+ efl_canvas_text_style_set(tb, buf);
+ ck_assert_str_eq(efl_canvas_text_style_get(tb), buf);
+
+ efl_text_set(tb, "hello world");
+ start = efl_canvas_text_cursor_new(tb);
+ end = efl_canvas_text_cursor_new(tb);
+ efl_canvas_text_cursor_pos_set(tb, start, 0);
+ efl_canvas_text_cursor_pos_set(tb, end, 4);
+
+ efl_canvas_text_annotation_insert(tb, start, end, "sz");
+ buf =
+ "DEFAULT='font=Sans font_size=12 color=#fff'";
+ efl_canvas_text_style_set(tb, buf);
+
+ evas_object_textblock_size_native_get(tb, &bw, NULL);
+
+ buf =
+ "DEFAULT='font=Sans font_size=16 color=#fff'";
+ efl_canvas_text_style_set(tb, buf);
+ evas_object_textblock_size_native_get(tb, &w, NULL);
+ ck_assert_int_gt(w, bw);
+
+ bw = w;
+ buf = "DEFAULT='left_margin=4 right_margin=4'";
+ efl_canvas_text_style_user_push(tb, buf);
+ ck_assert_str_eq(efl_canvas_text_style_user_peek(tb), buf);
+ evas_object_textblock_size_native_get(tb, &w, NULL);
+ ck_assert_int_gt(w, bw);
+ efl_canvas_text_style_user_pop(tb);
+ evas_object_textblock_size_native_get(tb, &w, NULL);
+ ck_assert_int_eq(w, bw);
+
+ END_TB_TEST();
+}
+END_TEST;
+
+START_TEST(efl_canvas_text_cursor)
+{
+ START_TB_TEST();
+
+#ifdef HAVE_FRIBIDI
+ Evas_Coord x, x2;
+ Evas_Coord nw, nh;
+ Evas_Coord cx, cx2;
+
+ /* Split cursor in LTR paragraph.
+ * Russian 't' in the beginnning to create additional item.*/
+ /*01234 5 6789012345678 19 01234 */
+ efl_text_set(tb, "тest \u202bנסיוןabcנסיון\u202c bang");
+ efl_canvas_text_size_native_get(tb, &nw, &nh);
+ efl_gfx_size_set(tb, nw, nh);
+
+ /* Logical cursor after "test " */
+ efl_canvas_text_cursor_pos_set(tb, cur, 6);
+ fail_if(!efl_canvas_text_cursor_geometry_get(tb, cur,
+ EFL_CANVAS_TEXT_CURSOR_TYPE_BEFORE, &cx, NULL, NULL, NULL, &cx2,
+ NULL, NULL, NULL));
+ efl_canvas_text_cursor_pos_set(tb, cur, 18);
+ evas_textblock_cursor_pen_geometry_get(cur, &x, NULL, NULL, NULL);
+ efl_canvas_text_cursor_pos_set(tb, cur, 20);
+ evas_textblock_cursor_pen_geometry_get(cur, &x2, NULL, NULL, NULL);
+ ck_assert_int_eq(cx, x);
+ ck_assert_int_eq(cx2, x2);
+#endif
+
+ END_TB_TEST();
+}
+END_TEST
+
void evas_test_textblock(TCase *tc)
{
tcase_add_test(tc, evas_textblock_simple);
@@ -3998,5 +4381,9 @@ void evas_test_textblock(TCase *tc)
#ifdef HAVE_HYPHEN
tcase_add_test(tc, evas_textblock_hyphenation);
#endif
+ tcase_add_test(tc, evas_textblock_text_iface);
+ tcase_add_test(tc, evas_textblock_annotation);
+ tcase_add_test(tc, efl_canvas_text_style);
+ tcase_add_test(tc, efl_canvas_text_cursor);
}