2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @section Evas_Object_Textblock_Internal Internal Textblock Object Tutorial
|
|
|
|
*
|
2010-08-16 01:22:18 -07:00
|
|
|
* This explains the internal design of the Evas Textblock Object, it's assumed
|
|
|
|
* that the reader of this section has already read @ref Evas_Object_Textblock_Tutorial "Textblock's usage docs.".
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
2010-08-16 01:22:18 -07:00
|
|
|
* @subsection textblock_internal_intro Introduction
|
2010-08-10 07:36:48 -07:00
|
|
|
* There are two main parts to the textblock object, the first being the node
|
|
|
|
* system, and the second being the layout system. The former is just an
|
|
|
|
* internal representation of the markup text, while the latter is the internal
|
|
|
|
* visual representation of the text (i.e positioning, sizing, fonts and etc).
|
|
|
|
*
|
|
|
|
* @subsection textblock_nodes The Nodes system
|
|
|
|
* The nodes mechanism consists of two main data types:
|
|
|
|
* ::Evas_Object_Textblock_Node_Text and ::Evas_Object_Textblock_Node_Format
|
|
|
|
* the former is for Text nodes and the latter is for format nodes.
|
|
|
|
* There's always at least one text node, even if there are only formats.
|
|
|
|
*
|
|
|
|
* @subsection textblock_nodes_text Text nodes
|
|
|
|
* Each text node is essentially a paragraph, it includes an @ref Eina_UStrbuf
|
|
|
|
* that stores the actual paragraph text, a utf8 string to store the paragraph
|
|
|
|
* text in utf8 (which is not used internally at all), A pointer to it's
|
2010-08-16 01:22:18 -07:00
|
|
|
* main @ref textblock_nodes_format_internal "Format Node" and the paragraph's
|
2010-08-10 07:36:48 -07:00
|
|
|
* @ref evas_bidi_props "BiDi properties". The pointer to the format node may be
|
|
|
|
* NULL if there's no format node anywhere before the end of the text node,
|
|
|
|
* not even in previous text nodes. If not NULL, it points to the first format
|
|
|
|
* node pointing to text inside of the text node, or if there is none, it points
|
|
|
|
* to the previous's text nodes format node. Each paragraph has a format node
|
|
|
|
* representing a paragraph separator pointing to it's last position except
|
|
|
|
* for the last paragraph, which has no such constraint. This constraint
|
|
|
|
* happens because text nodes are paragraphs and paragraphs are delimited by
|
|
|
|
* paragraph separators.
|
|
|
|
*
|
2010-08-16 01:22:18 -07:00
|
|
|
* @subsection textblock_nodes_format_internal Format Nodes - Internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* Each format node stores a group of format information, for example the
|
|
|
|
* markup: \<font=Vera,Kochi font_size=10 align=left\> will all be inserted
|
|
|
|
* inside the same format node, altohugh it consists of different formatting
|
|
|
|
* commands.
|
|
|
|
* Each node has a pointer to it's text node, this pointer is NEVER NULL, even
|
|
|
|
* if there's only one format, and no text, a text node is created. Each format
|
|
|
|
* node includes an offset from the last format node of the same text node. For
|
|
|
|
* example, the markup "0<b>12</b>" will create two format nodes, the first
|
|
|
|
* having an offset of 1 and the second an offset of 2. Each format node also
|
|
|
|
* includes a @ref Eina_Strbuf that includes the textual representation of the
|
|
|
|
* format, and a boolean stating if the format is a visible format or not, see
|
|
|
|
* @ref textblock_nodes_format_visible
|
|
|
|
*
|
|
|
|
* @subsection textblock_nodes_format_visible Visible Format Nodes
|
|
|
|
* There are two types of format nodes, visible and invisible. They are the same
|
|
|
|
* in every way, except for the representation in the text node. While invisible
|
|
|
|
* format nodes have no representation in the text node, the visible ones do.
|
2010-08-16 01:36:08 -07:00
|
|
|
* The Uniceode object replacement character (0xFFFC) is inserted to every place
|
|
|
|
* a visible format node points to. This makes it very easy to treat visible
|
2010-08-10 07:36:48 -07:00
|
|
|
* formats as items in the text, both for BiDi purposes and cursor handling
|
|
|
|
* purposes.
|
|
|
|
* Here are a few example visible an invisible formats:
|
|
|
|
* Visible: newline char, tab, paragraph separator and an embedded item.
|
|
|
|
* Invisible: setting the color, font or alignment of the text.
|
|
|
|
*
|
|
|
|
* @subsection textblock_layout The layout system
|
|
|
|
* @todo write @ref textblock_layout
|
|
|
|
*/
|
2011-01-30 02:31:08 -08:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
#include "evas_common.h"
|
|
|
|
#include "evas_private.h"
|
|
|
|
|
2011-05-05 04:06:06 -07:00
|
|
|
#ifdef HAVE_LINEBREAK
|
|
|
|
#include "linebreak.h"
|
|
|
|
#endif
|
|
|
|
|
2005-01-30 06:48:30 -08:00
|
|
|
/* save typing */
|
2005-01-29 08:28:18 -08:00
|
|
|
#define ENFN obj->layer->evas->engine.func
|
|
|
|
#define ENDT obj->layer->evas->engine.data.output
|
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
/* private magic number for textblock objects */
|
|
|
|
static const char o_type[] = "textblock";
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/* The char to be inserted instead of visible formats */
|
2010-08-16 01:36:08 -07:00
|
|
|
#define EVAS_TEXTBLOCK_REPLACEMENT_CHAR 0xFFFC
|
2011-05-05 06:38:04 -07:00
|
|
|
#define _PARAGRAPH_SEPARATOR 0x2029
|
|
|
|
#define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \
|
|
|
|
(((ch) == EVAS_TEXTBLOCK_REPLACEMENT_CHAR) || \
|
|
|
|
((ch) == '\n') || \
|
|
|
|
((ch) == '\t') || \
|
|
|
|
((ch) == _PARAGRAPH_SEPARATOR))
|
2005-01-08 02:02:18 -08:00
|
|
|
|
|
|
|
/* private struct for textblock object internal data */
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock
|
|
|
|
* The actual textblock object.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Textblock Evas_Object_Textblock;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Style_Tag
|
|
|
|
* The structure used for finding style tags.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Node_Text
|
|
|
|
* A text node.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Node_Text Evas_Object_Textblock_Node_Text;
|
|
|
|
/*
|
|
|
|
* Defined in Evas.h
|
|
|
|
typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format;
|
|
|
|
*/
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Paragraph
|
|
|
|
* A layouting paragraph.
|
|
|
|
*/
|
2010-07-28 05:00:41 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Paragraph Evas_Object_Textblock_Paragraph;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Line
|
|
|
|
* A layouting line.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Line Evas_Object_Textblock_Line;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Item
|
|
|
|
* A layouting item.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Item Evas_Object_Textblock_Item;
|
2011-01-30 02:31:16 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @typedef Evas_Object_Textblock_Item
|
|
|
|
* A layouting text item.
|
|
|
|
*/
|
|
|
|
typedef struct _Evas_Object_Textblock_Text_Item Evas_Object_Textblock_Text_Item;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Format_Item
|
|
|
|
* A layouting format item.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Format_Item Evas_Object_Textblock_Format_Item;
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @typedef Evas_Object_Textblock_Format
|
|
|
|
* A textblock format.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format;
|
2005-01-29 08:28:18 -08:00
|
|
|
|
2011-04-13 01:36:57 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @def IS_AT_END(ti, ind)
|
|
|
|
* Return true if ind is at the end of the text item, false otherwise.
|
|
|
|
*/
|
|
|
|
#define IS_AT_END(ti, ind) (ind == ti->text_props.text_len)
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @def GET_PREV(text, ind)
|
|
|
|
* Gets the index of the previous char in the text text, this simply returns
|
|
|
|
* the current char pointed to and decrements ind but ensures it stays in
|
|
|
|
* the text range.
|
|
|
|
*/
|
2011-04-13 01:36:57 -07:00
|
|
|
#define GET_PREV(text, ind) ((text) ? (((ind) > 0) ? ((text)[(ind)--]) : \
|
|
|
|
((text)[ind])) : 0)
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @def GET_NEXT(text, ind)
|
|
|
|
* Gets the index of the next in the text text, this simply returns
|
|
|
|
* the current char pointed to and increments indd but ensures it stays in
|
|
|
|
* the text range.
|
|
|
|
*/
|
2011-04-13 01:36:57 -07:00
|
|
|
#define GET_NEXT(text, ti, ind) (((text) && !IS_AT_END(ti, (size_t) ind)) ? \
|
|
|
|
((text)[(ind)++]) : 0)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @def GET_ITEM_TEXT(ti)
|
|
|
|
* Returns a const reference to the text of the ti (not null terminated).
|
|
|
|
*/
|
|
|
|
#define GET_ITEM_TEXT(ti) \
|
|
|
|
(((ti)->parent.text_node) ? \
|
|
|
|
(eina_ustrbuf_string_get((ti)->parent.text_node->unicode) + \
|
|
|
|
(ti)->parent.text_pos) : EINA_UNICODE_EMPTY_STRING)
|
2005-02-19 08:05:12 -08:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/*FIXME: document the structs and struct items. */
|
2005-08-20 22:13:49 -07:00
|
|
|
struct _Evas_Object_Style_Tag
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2005-08-20 22:13:49 -07:00
|
|
|
char *tag;
|
|
|
|
char *replace;
|
2010-02-26 14:32:07 -08:00
|
|
|
size_t tag_len;
|
|
|
|
size_t replace_len;
|
2005-08-20 22:13:49 -07:00
|
|
|
};
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
struct _Evas_Object_Textblock_Node_Text
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2010-08-09 09:24:17 -07:00
|
|
|
Eina_UStrbuf *unicode;
|
2010-09-01 06:15:04 -07:00
|
|
|
char *utf8;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *format_node;
|
2011-04-14 05:13:20 -07:00
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
2011-01-30 02:40:14 -08:00
|
|
|
Eina_Bool dirty : 1;
|
2011-04-07 04:24:11 -07:00
|
|
|
Eina_Bool new : 1;
|
2010-08-09 09:24:17 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Evas_Object_Textblock_Node_Format
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
|
|
|
Eina_Strbuf *format;
|
|
|
|
Evas_Object_Textblock_Node_Text *text_node;
|
|
|
|
size_t offset;
|
2011-04-27 05:41:26 -07:00
|
|
|
Eina_Bool visible : 1;
|
|
|
|
Eina_Bool new : 1;
|
2005-08-05 03:08:05 -07:00
|
|
|
};
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @def _NODE_TEXT(x)
|
|
|
|
* A convinience macro for casting to a text node.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
#define _NODE_TEXT(x) ((Evas_Object_Textblock_Node_Text *) (x))
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-30 04:27:39 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* @def _NODE_FORMAT(x)
|
|
|
|
* A convinience macro for casting to a format node.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
#define _NODE_FORMAT(x) ((Evas_Object_Textblock_Node_Format *) (x))
|
2011-01-30 02:31:16 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @def _ITEM(x)
|
|
|
|
* A convinience macro for casting to a generic item.
|
|
|
|
*/
|
|
|
|
#define _ITEM(x) ((Evas_Object_Textblock_Item *) (x))
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @def _ITEM_TEXT(x)
|
|
|
|
* A convinience macro for casting to a text item.
|
|
|
|
*/
|
|
|
|
#define _ITEM_TEXT(x) ((Evas_Object_Textblock_Text_Item *) (x))
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @def _ITEM_FORMAT(x)
|
|
|
|
* A convinience macro for casting to a format item.
|
|
|
|
*/
|
|
|
|
#define _ITEM_FORMAT(x) ((Evas_Object_Textblock_Format_Item *) (x))
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
struct _Evas_Object_Textblock_Paragraph
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
|
|
|
Evas_Object_Textblock_Line *lines;
|
2011-01-30 02:39:52 -08:00
|
|
|
Evas_Object_Textblock_Node_Text *text_node;
|
2011-01-30 02:40:14 -08:00
|
|
|
Eina_List *logical_items;
|
2011-04-14 05:13:20 -07:00
|
|
|
Evas_BiDi_Paragraph_Props *bidi_props;
|
2011-01-30 02:40:04 -08:00
|
|
|
int x, y, w, h;
|
2011-01-30 02:39:47 -08:00
|
|
|
int line_no;
|
2011-04-11 06:44:01 -07:00
|
|
|
Eina_Bool visible;
|
2010-08-09 09:24:17 -07:00
|
|
|
};
|
2010-07-28 05:00:41 -07:00
|
|
|
|
2005-08-08 02:01:07 -07:00
|
|
|
struct _Evas_Object_Textblock_Line
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2005-08-20 22:13:49 -07:00
|
|
|
Evas_Object_Textblock_Item *items;
|
2011-01-30 02:39:47 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
2011-01-30 02:45:45 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ellip_ti;
|
2005-08-20 22:13:49 -07:00
|
|
|
int x, y, w, h;
|
|
|
|
int baseline;
|
|
|
|
int line_no;
|
2005-08-08 02:01:07 -07:00
|
|
|
};
|
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
typedef enum _Evas_Textblock_Item_Type
|
|
|
|
{
|
|
|
|
EVAS_TEXTBLOCK_ITEM_TEXT,
|
|
|
|
EVAS_TEXTBLOCK_ITEM_FORMAT,
|
|
|
|
} Evas_Textblock_Item_Type;
|
|
|
|
|
2005-08-08 02:01:07 -07:00
|
|
|
struct _Evas_Object_Textblock_Item
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2011-01-30 02:31:16 -08:00
|
|
|
Evas_Textblock_Item_Type type;
|
|
|
|
Evas_Object_Textblock_Node_Text *text_node;
|
2011-01-30 02:40:47 -08:00
|
|
|
Evas_Object_Textblock_Format *format;
|
2011-01-30 02:31:16 -08:00
|
|
|
size_t text_pos;
|
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
size_t visual_pos;
|
|
|
|
#endif
|
2011-01-30 02:33:19 -08:00
|
|
|
Evas_Coord adv, x, w, h;
|
2011-01-30 02:40:30 -08:00
|
|
|
Eina_Bool merge : 1; /* Indicates whether this
|
|
|
|
item should merge to the
|
|
|
|
previous item or not */
|
|
|
|
Eina_Bool visually_deleted : 1;
|
|
|
|
/* Indicates whether this
|
|
|
|
item is used in the visual
|
|
|
|
layout or not. */
|
2011-01-30 02:31:16 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Evas_Object_Textblock_Text_Item
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item parent;
|
2011-02-14 05:09:41 -08:00
|
|
|
Evas_Text_Props text_props;
|
2010-08-09 09:24:17 -07:00
|
|
|
int inset, baseline;
|
2011-03-29 06:52:35 -07:00
|
|
|
Evas_Coord x_adjustment; /* Used to indicate by how
|
|
|
|
much we adjusted sizes */
|
2005-08-08 02:01:07 -07:00
|
|
|
};
|
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
struct _Evas_Object_Textblock_Format_Item
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
Evas_Object_Textblock_Item parent;
|
2011-02-14 05:09:41 -08:00
|
|
|
Evas_BiDi_Direction bidi_dir;
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *item;
|
|
|
|
Evas_Object_Textblock_Node_Format *source_node;
|
2011-01-30 02:31:16 -08:00
|
|
|
int y, ascent, descent;
|
2010-08-09 09:24:17 -07:00
|
|
|
unsigned char vsize : 2;
|
|
|
|
unsigned char size : 2;
|
|
|
|
unsigned char formatme : 1;
|
2005-08-20 22:13:49 -07:00
|
|
|
};
|
|
|
|
|
2005-08-08 02:01:07 -07:00
|
|
|
struct _Evas_Object_Textblock_Format
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2005-08-08 02:01:07 -07:00
|
|
|
double halign;
|
|
|
|
double valign;
|
|
|
|
struct {
|
2006-05-31 11:33:46 -07:00
|
|
|
const char *name;
|
|
|
|
const char *source;
|
|
|
|
const char *fallbacks;
|
2005-08-08 02:01:07 -07:00
|
|
|
void *font;
|
2011-04-11 05:05:59 -07:00
|
|
|
int size;
|
2005-08-08 02:01:07 -07:00
|
|
|
} font;
|
|
|
|
struct {
|
|
|
|
struct {
|
|
|
|
unsigned char r, g, b, a;
|
2005-08-15 08:30:30 -07:00
|
|
|
} normal, underline, underline2, outline, shadow, glow, glow2, backing,
|
2005-08-08 02:01:07 -07:00
|
|
|
strikethrough;
|
|
|
|
} color;
|
|
|
|
struct {
|
|
|
|
int l, r;
|
|
|
|
} margin;
|
2011-04-11 05:05:59 -07:00
|
|
|
int ref;
|
2005-08-15 08:39:31 -07:00
|
|
|
int tabstops;
|
2009-09-03 20:53:18 -07:00
|
|
|
int linesize;
|
2010-04-12 01:23:53 -07:00
|
|
|
int linegap;
|
2011-04-11 05:05:59 -07:00
|
|
|
double linerelsize;
|
2010-04-12 01:23:53 -07:00
|
|
|
double linerelgap;
|
2010-06-19 23:32:05 -07:00
|
|
|
double linefill;
|
2011-01-30 02:45:45 -08:00
|
|
|
double ellipsis;
|
2011-04-11 05:05:59 -07:00
|
|
|
Eina_Bool halign_auto;
|
2005-08-08 02:01:07 -07:00
|
|
|
unsigned char style;
|
|
|
|
unsigned char wrap_word : 1;
|
|
|
|
unsigned char wrap_char : 1;
|
2011-01-30 02:44:03 -08:00
|
|
|
unsigned char wrap_mixed : 1;
|
2005-08-08 02:01:07 -07:00
|
|
|
unsigned char underline : 1;
|
|
|
|
unsigned char underline2 : 1;
|
|
|
|
unsigned char strikethrough : 1;
|
|
|
|
unsigned char backing : 1;
|
2011-04-28 04:08:20 -07:00
|
|
|
unsigned char password : 1;
|
2005-08-05 03:08:05 -07:00
|
|
|
};
|
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
struct _Evas_Textblock_Style
|
2005-01-29 08:28:18 -08:00
|
|
|
{
|
2011-02-24 00:43:34 -08:00
|
|
|
const char *style_text;
|
2005-08-05 03:08:05 -07:00
|
|
|
char *default_tag;
|
2005-08-03 06:07:00 -07:00
|
|
|
Evas_Object_Style_Tag *tags;
|
2008-10-21 09:31:05 -07:00
|
|
|
Eina_List *objects;
|
2005-08-05 03:08:05 -07:00
|
|
|
unsigned char delete_me : 1;
|
2005-01-29 08:28:18 -08:00
|
|
|
};
|
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
struct _Evas_Textblock_Cursor
|
2005-01-29 08:28:18 -08:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object *obj;
|
2010-08-18 06:56:34 -07:00
|
|
|
size_t pos;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *node;
|
|
|
|
|
2005-01-29 08:28:18 -08:00
|
|
|
};
|
2005-01-08 02:02:18 -08:00
|
|
|
|
|
|
|
struct _Evas_Object_Textblock
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
DATA32 magic;
|
|
|
|
Evas_Textblock_Style *style;
|
|
|
|
Evas_Textblock_Cursor *cursor;
|
|
|
|
Eina_List *cursors;
|
|
|
|
Evas_Object_Textblock_Node_Text *text_nodes;
|
|
|
|
Evas_Object_Textblock_Node_Format *format_nodes;
|
|
|
|
Evas_Object_Textblock_Paragraph *paragraphs;
|
2011-03-30 03:31:29 -07:00
|
|
|
int last_w, last_h;
|
2005-08-16 01:12:14 -07:00
|
|
|
struct {
|
2010-08-09 09:24:17 -07:00
|
|
|
int l, r, t, b;
|
2005-08-16 01:12:14 -07:00
|
|
|
} style_pad;
|
2011-03-30 03:31:29 -07:00
|
|
|
double valign;
|
2010-08-09 09:24:17 -07:00
|
|
|
char *markup_text;
|
|
|
|
void *engine_data;
|
|
|
|
const char *repch;
|
2011-04-14 08:34:01 -07:00
|
|
|
const char *bidi_delimiters;
|
2005-08-27 23:41:54 -07:00
|
|
|
struct {
|
2010-08-09 09:24:17 -07:00
|
|
|
int w, h;
|
|
|
|
unsigned char valid : 1;
|
2005-08-27 23:41:54 -07:00
|
|
|
} formatted, native;
|
2010-08-09 09:24:17 -07:00
|
|
|
unsigned char redraw : 1;
|
|
|
|
unsigned char changed : 1;
|
2011-01-30 02:40:36 -08:00
|
|
|
unsigned char content_changed : 1;
|
2011-04-27 05:41:26 -07:00
|
|
|
Eina_Bool format_changed : 1;
|
2011-03-30 03:38:02 -07:00
|
|
|
unsigned char have_ellipsis : 1;
|
2011-02-14 06:17:12 -08:00
|
|
|
Eina_Bool newline_is_ps : 1;
|
2005-01-08 02:02:18 -08:00
|
|
|
};
|
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
/* private methods for textblock objects */
|
|
|
|
static void evas_object_textblock_init(Evas_Object *obj);
|
|
|
|
static void *evas_object_textblock_new(void);
|
|
|
|
static void evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
|
|
|
|
static void evas_object_textblock_free(Evas_Object *obj);
|
|
|
|
static void evas_object_textblock_render_pre(Evas_Object *obj);
|
|
|
|
static void evas_object_textblock_render_post(Evas_Object *obj);
|
2005-02-24 02:29:04 -08:00
|
|
|
|
2008-08-30 19:04:31 -07:00
|
|
|
static unsigned int evas_object_textblock_id_get(Evas_Object *obj);
|
|
|
|
static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj);
|
2008-08-25 22:45:04 -07:00
|
|
|
static void *evas_object_textblock_engine_data_get(Evas_Object *obj);
|
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
static int evas_object_textblock_is_opaque(Evas_Object *obj);
|
|
|
|
static int evas_object_textblock_was_opaque(Evas_Object *obj);
|
2005-01-29 08:28:18 -08:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
static void evas_object_textblock_coords_recalc(Evas_Object *obj);
|
2005-02-19 08:05:12 -08:00
|
|
|
|
2008-11-15 02:39:46 -08:00
|
|
|
static void evas_object_textblock_scale_update(Evas_Object *obj);
|
|
|
|
|
2007-05-06 04:29:37 -07:00
|
|
|
static const Evas_Object_Func object_func =
|
2005-02-19 08:05:12 -08:00
|
|
|
{
|
2005-08-03 06:07:00 -07:00
|
|
|
/* methods (compulsory) */
|
|
|
|
evas_object_textblock_free,
|
|
|
|
evas_object_textblock_render,
|
|
|
|
evas_object_textblock_render_pre,
|
|
|
|
evas_object_textblock_render_post,
|
2008-08-30 19:04:31 -07:00
|
|
|
evas_object_textblock_id_get,
|
|
|
|
evas_object_textblock_visual_id_get,
|
2008-08-25 22:45:04 -07:00
|
|
|
evas_object_textblock_engine_data_get,
|
2005-08-03 06:07:00 -07:00
|
|
|
/* these are optional. NULL = nothing */
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
evas_object_textblock_is_opaque,
|
|
|
|
evas_object_textblock_was_opaque,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2008-11-15 02:39:46 -08:00
|
|
|
evas_object_textblock_coords_recalc,
|
2009-02-16 20:53:03 -08:00
|
|
|
evas_object_textblock_scale_update,
|
|
|
|
NULL,
|
2009-10-28 01:59:01 -07:00
|
|
|
NULL,
|
2009-02-16 20:53:03 -08:00
|
|
|
NULL
|
2005-08-03 06:07:00 -07:00
|
|
|
};
|
2005-02-19 08:05:12 -08:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
/* the actual api call to add a textblock */
|
the textblock actually works.
so far the following works:
o = evas_object_textblock_add(evas);
evas_object_move(o, 10, 40);
evas_object_resize(o, win_w - 20, win_h - 50);
evas_object_textblock_format_insert(o, "color=#000000ff");
evas_object_textblock_format_insert(o, "font=/usr/local/share/expedite/data/Vera.ttf size=10");
evas_object_textblock_text_insert(o, "This is 1 line. ");
evas_object_textblock_text_insert(o, "And some more text. ");
evas_object_textblock_format_insert(o, "size=20");
evas_object_textblock_format_insert(o, "color=#f80");
evas_object_textblock_text_insert(o, "Bigger orange text.");
evas_object_textblock_format_insert(o, "size=8");
evas_object_textblock_format_insert(o, "color=#0000ff88");
evas_object_textblock_format_insert(o, "\n");
evas_object_textblock_text_insert(o, "A second line of transparent blue.");
evas_object_show(o);
i need to implement alignment handling next...
SVN revision: 13135
2005-01-30 02:22:47 -08:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
#define TB_HEAD() \
|
|
|
|
Evas_Object_Textblock *o; \
|
|
|
|
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
|
|
|
|
return; \
|
|
|
|
MAGIC_CHECK_END(); \
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data); \
|
|
|
|
MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
|
|
|
|
return; \
|
|
|
|
MAGIC_CHECK_END();
|
2005-02-23 12:32:07 -08:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
#define TB_HEAD_RETURN(x) \
|
|
|
|
Evas_Object_Textblock *o; \
|
|
|
|
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
|
|
|
|
return (x); \
|
|
|
|
MAGIC_CHECK_END(); \
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data); \
|
|
|
|
MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
|
|
|
|
return (x); \
|
|
|
|
MAGIC_CHECK_END();
|
2005-05-21 19:49:50 -07:00
|
|
|
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-08-29 02:13:48 -07:00
|
|
|
static Eina_Bool _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur);
|
2010-08-25 07:37:52 -07:00
|
|
|
static void _evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n);
|
|
|
|
static void _evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n, int start, int end);
|
2010-08-09 09:24:17 -07:00
|
|
|
static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur);
|
|
|
|
static size_t _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt);
|
|
|
|
static Eina_Bool _evas_textblock_format_is_visible(const char *s);
|
2010-08-18 05:29:20 -07:00
|
|
|
static void _evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment);
|
2010-08-09 09:24:17 -07:00
|
|
|
static void _evas_textblock_node_format_free(Evas_Object_Textblock_Node_Format *n);
|
|
|
|
static void _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n);
|
2011-04-07 04:24:11 -07:00
|
|
|
static void _evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj);
|
2011-04-07 04:24:15 -07:00
|
|
|
static void _evas_textblock_invalidate_all(Evas_Object_Textblock *o);
|
2010-08-18 06:56:34 -07:00
|
|
|
static void _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset);
|
2010-08-12 07:59:42 -07:00
|
|
|
static void _evas_textblock_cursors_set_node(Evas_Object_Textblock *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node);
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
/* styles */
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-02-24 00:43:34 -08:00
|
|
|
* Clears the textblock style passed except for the style_text which is replaced.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @param ts The ts to be cleared. Must not be NULL.
|
2011-02-24 00:43:34 -08:00
|
|
|
* @param style_text the style's text.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-03 06:07:00 -07:00
|
|
|
static void
|
2011-02-24 00:43:34 -08:00
|
|
|
_style_replace(Evas_Textblock_Style *ts, const char *style_text)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2011-02-24 00:43:34 -08:00
|
|
|
eina_stringshare_replace(&ts->style_text, style_text);
|
2005-08-03 06:07:00 -07:00
|
|
|
if (ts->default_tag) free(ts->default_tag);
|
|
|
|
while (ts->tags)
|
2005-02-19 08:05:12 -08:00
|
|
|
{
|
2005-08-03 06:07:00 -07:00
|
|
|
Evas_Object_Style_Tag *tag;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-03 06:07:00 -07:00
|
|
|
tag = (Evas_Object_Style_Tag *)ts->tags;
|
2008-10-17 04:23:18 -07:00
|
|
|
ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
|
2005-08-03 06:07:00 -07:00
|
|
|
free(tag->tag);
|
|
|
|
free(tag->replace);
|
|
|
|
free(tag);
|
2005-02-19 08:05:12 -08:00
|
|
|
}
|
2005-08-03 06:07:00 -07:00
|
|
|
ts->default_tag = NULL;
|
|
|
|
ts->tags = NULL;
|
the textblock actually works.
so far the following works:
o = evas_object_textblock_add(evas);
evas_object_move(o, 10, 40);
evas_object_resize(o, win_w - 20, win_h - 50);
evas_object_textblock_format_insert(o, "color=#000000ff");
evas_object_textblock_format_insert(o, "font=/usr/local/share/expedite/data/Vera.ttf size=10");
evas_object_textblock_text_insert(o, "This is 1 line. ");
evas_object_textblock_text_insert(o, "And some more text. ");
evas_object_textblock_format_insert(o, "size=20");
evas_object_textblock_format_insert(o, "color=#f80");
evas_object_textblock_text_insert(o, "Bigger orange text.");
evas_object_textblock_format_insert(o, "size=8");
evas_object_textblock_format_insert(o, "color=#0000ff88");
evas_object_textblock_format_insert(o, "\n");
evas_object_textblock_text_insert(o, "A second line of transparent blue.");
evas_object_show(o);
i need to implement alignment handling next...
SVN revision: 13135
2005-01-30 02:22:47 -08:00
|
|
|
}
|
|
|
|
|
2011-02-24 00:43:34 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Clears the textblock style passed.
|
|
|
|
* @param ts The ts to be cleared. Must not be NULL.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_style_clear(Evas_Textblock_Style *ts)
|
|
|
|
{
|
|
|
|
_style_replace(ts, NULL);
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Searches inside the tags stored in the style for the tag who's
|
|
|
|
* replacement is s of size replace_len;
|
|
|
|
* @param ts The ts to be cleared. Must not be NULL.
|
|
|
|
* @param s The replace string to match.
|
|
|
|
* @param replace_len the length of the replace string.
|
|
|
|
* @param[out] tag_len The length of the tag found. - Must not be NULL.
|
|
|
|
* @return The tag found.
|
|
|
|
*/
|
2010-02-26 14:32:07 -08:00
|
|
|
static inline const char *
|
|
|
|
_style_match_replace(Evas_Textblock_Style *ts, const char *s, size_t replace_len, size_t *tag_len)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Style_Tag *tag;
|
|
|
|
|
2008-10-21 05:19:57 -07:00
|
|
|
EINA_INLIST_FOREACH(ts->tags, tag)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-02-26 14:32:07 -08:00
|
|
|
if (tag->replace_len != replace_len) continue;
|
|
|
|
if (!strcmp(tag->replace, s))
|
|
|
|
{
|
|
|
|
*tag_len = tag->tag_len;
|
|
|
|
return tag->tag;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2010-02-26 14:32:07 -08:00
|
|
|
*tag_len = 0;
|
2005-08-05 03:08:05 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Searches inside the tags stored in the style for the tag matching s.
|
|
|
|
* @param ts The ts to be cleared. Must not be NULL.
|
|
|
|
* @param s The tag to be matched.
|
|
|
|
* @param tag_len the length of the tag string.
|
|
|
|
* @param[out] replace_len The length of the replcaement found. - Must not be NULL.
|
|
|
|
* @return The replacement string found.
|
|
|
|
*/
|
2010-02-26 14:32:07 -08:00
|
|
|
static inline const char *
|
|
|
|
_style_match_tag(Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Style_Tag *tag;
|
2005-08-15 05:46:16 -07:00
|
|
|
|
2008-10-21 05:19:57 -07:00
|
|
|
EINA_INLIST_FOREACH(ts->tags, tag)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-02-26 14:32:07 -08:00
|
|
|
if (tag->tag_len != tag_len) continue;
|
|
|
|
if (!strcmp(tag->tag, s))
|
|
|
|
{
|
|
|
|
*replace_len = tag->replace_len;
|
|
|
|
return tag->replace;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2010-02-26 14:32:07 -08:00
|
|
|
*replace_len = 0;
|
2005-08-05 03:08:05 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Clears all the nodes (text and format) of the textblock object.
|
|
|
|
* @param obj The evas object, must not be NULL.
|
|
|
|
*/
|
2005-08-05 03:08:05 -07:00
|
|
|
static void
|
2008-02-08 14:35:19 -08:00
|
|
|
_nodes_clear(const Evas_Object *obj)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
while (o->text_nodes)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
|
|
|
|
n = o->text_nodes;
|
2011-01-30 02:31:08 -08:00
|
|
|
o->text_nodes = _NODE_TEXT(eina_inlist_remove(
|
|
|
|
EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n)));
|
|
|
|
_evas_textblock_node_text_free(n);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
while (o->format_nodes)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *n;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
n = o->format_nodes;
|
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_remove(EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n)));
|
|
|
|
_evas_textblock_node_format_free(n);
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Unrefs and frees (if needed) a textblock format.
|
|
|
|
* @param obj The Evas_Object, Must not be NULL.
|
|
|
|
* @param fmt the format to be cleaned, must not be NULL.
|
|
|
|
*/
|
2005-08-08 05:43:59 -07:00
|
|
|
static void
|
2010-07-28 05:00:41 -07:00
|
|
|
_format_unref_free(const Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
|
2005-08-08 05:43:59 -07:00
|
|
|
{
|
|
|
|
fmt->ref--;
|
|
|
|
if (fmt->ref > 0) return;
|
2008-10-15 07:38:34 -07:00
|
|
|
if (fmt->font.name) eina_stringshare_del(fmt->font.name);
|
|
|
|
if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
|
|
|
|
if (fmt->font.source) eina_stringshare_del(fmt->font.source);
|
2005-08-08 05:43:59 -07:00
|
|
|
evas_font_free(obj->layer->evas, fmt->font.font);
|
|
|
|
free(fmt);
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:36:39 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Free a layout item
|
|
|
|
* @param obj The evas object, must not be NULL.
|
|
|
|
* @param ln the layout line on which the item is in, must not be NULL.
|
|
|
|
* @param it the layout item to be freed
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_item_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln, Evas_Object_Textblock_Item *it)
|
|
|
|
{
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
|
|
|
|
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_content_unref(&ti->text_props);
|
2011-01-30 02:36:39 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
|
|
|
|
|
|
|
|
if (fi->item) eina_stringshare_del(fi->item);
|
|
|
|
}
|
2011-01-30 02:40:47 -08:00
|
|
|
_format_unref_free(obj, it->format);
|
2011-01-30 02:36:39 -08:00
|
|
|
if (ln)
|
|
|
|
{
|
|
|
|
ln->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(
|
|
|
|
EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items));
|
|
|
|
}
|
|
|
|
free(it);
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Free a layout line.
|
|
|
|
* @param obj The evas object, must not be NULL.
|
|
|
|
* @param ln the layout line to be freed, must not be NULL.
|
|
|
|
*/
|
2005-08-30 08:19:39 -07:00
|
|
|
static void
|
2011-01-30 02:45:45 -08:00
|
|
|
_line_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
/* Items are freed from the logical list, except for the ellip item */
|
|
|
|
if (ln->ellip_ti) _item_free(obj, NULL, _ITEM(ln->ellip_ti));
|
2006-01-19 06:16:47 -08:00
|
|
|
if (ln) free(ln);
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
|
2009-12-21 11:07:51 -08:00
|
|
|
/* table of html escapes (that i can find) this should be ordered with the
|
|
|
|
* most common first as it's a linear search to match - no hash for this.
|
|
|
|
*
|
|
|
|
* these are stored as one large string and one additional array that
|
|
|
|
* contains the offsets to the tokens for space efficiency.
|
|
|
|
*/
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @var escape_strings[]
|
|
|
|
* This string consists of NULL terminated pairs of strings, the first of
|
|
|
|
* every pair is an escape and the second is the value of the escape.
|
|
|
|
*/
|
2009-12-21 11:07:51 -08:00
|
|
|
static const char escape_strings[] =
|
2010-08-09 09:24:17 -07:00
|
|
|
/* most common escaped stuff */
|
|
|
|
" \0" "\x20\0" /* NOTE: this here to avoid escaping to   */
|
|
|
|
" \0" "\x20\0" /* NOTE: we allow nsbp's to break as we map early - maybe map to ascii 0x01 and then make the rendering code think 0x01 -> 0x20 */
|
|
|
|
""\0" "\x22\0"
|
|
|
|
"&\0" "\x26\0"
|
|
|
|
"<\0" "\x3c\0"
|
|
|
|
">\0" "\x3e\0"
|
|
|
|
/* all the rest */
|
|
|
|
"¡\0" "\xc2\xa1\0"
|
|
|
|
"¢\0" "\xc2\xa2\0"
|
|
|
|
"£\0" "\xc2\xa3\0"
|
|
|
|
"¤\0" "\xc2\xa4\0"
|
|
|
|
"¥\0" "\xc2\xa5\0"
|
|
|
|
"¦\0" "\xc2\xa6\0"
|
|
|
|
"§\0" "\xc2\xa7\0"
|
|
|
|
"¨\0" "\xc2\xa8\0"
|
|
|
|
"©\0" "\xc2\xa9\0"
|
|
|
|
"ª\0" "\xc2\xaa\0"
|
|
|
|
"«\0" "\xc2\xab\0"
|
|
|
|
"¬\0" "\xc2\xac\0"
|
|
|
|
"®\0" "\xc2\xae\0"
|
|
|
|
"¯\0" "\xc2\xaf\0"
|
|
|
|
"°\0" "\xc2\xb0\0"
|
|
|
|
"±\0" "\xc2\xb1\0"
|
|
|
|
"²\0" "\xc2\xb2\0"
|
|
|
|
"³\0" "\xc2\xb3\0"
|
|
|
|
"´\0" "\xc2\xb4\0"
|
|
|
|
"µ\0" "\xc2\xb5\0"
|
|
|
|
"¶\0" "\xc2\xb6\0"
|
|
|
|
"·\0" "\xc2\xb7\0"
|
|
|
|
"¸\0" "\xc2\xb8\0"
|
|
|
|
"¹\0" "\xc2\xb9\0"
|
|
|
|
"º\0" "\xc2\xba\0"
|
|
|
|
"»\0" "\xc2\xbb\0"
|
|
|
|
"¼\0" "\xc2\xbc\0"
|
|
|
|
"½\0" "\xc2\xbd\0"
|
|
|
|
"¾\0" "\xc2\xbe\0"
|
|
|
|
"¿\0" "\xc2\xbf\0"
|
|
|
|
"À\0" "\xc3\x80\0"
|
|
|
|
"Á\0" "\xc3\x81\0"
|
|
|
|
"Â\0" "\xc3\x82\0"
|
|
|
|
"Ã\0" "\xc3\x83\0"
|
|
|
|
"Ä\0" "\xc3\x84\0"
|
|
|
|
"Å\0" "\xc3\x85\0"
|
|
|
|
"&Aelig;\0" "\xc3\x86\0"
|
|
|
|
"Ç\0" "\xc3\x87\0"
|
|
|
|
"È\0" "\xc3\x88\0"
|
|
|
|
"É\0" "\xc3\x89\0"
|
|
|
|
"Ê\0" "\xc3\x8a\0"
|
|
|
|
"Ë\0" "\xc3\x8b\0"
|
|
|
|
"Ì\0" "\xc3\x8c\0"
|
|
|
|
"Í\0" "\xc3\x8d\0"
|
|
|
|
"Î\0" "\xc3\x8e\0"
|
|
|
|
"Ï\0" "\xc3\x8f\0"
|
|
|
|
"&Eth;\0" "\xc3\x90\0"
|
|
|
|
"Ñ\0" "\xc3\x91\0"
|
|
|
|
"Ò\0" "\xc3\x92\0"
|
|
|
|
"Ó\0" "\xc3\x93\0"
|
|
|
|
"Ô\0" "\xc3\x94\0"
|
|
|
|
"Õ\0" "\xc3\x95\0"
|
|
|
|
"Ö\0" "\xc3\x96\0"
|
|
|
|
"×\0" "\xc3\x97\0"
|
|
|
|
"Ø\0" "\xc3\x98\0"
|
|
|
|
"Ù\0" "\xc3\x99\0"
|
|
|
|
"Ú\0" "\xc3\x9a\0"
|
|
|
|
"Û\0" "\xc3\x9b\0"
|
|
|
|
"Ý\0" "\xc3\x9d\0"
|
|
|
|
"&Thorn;\0" "\xc3\x9e\0"
|
|
|
|
"ß\0" "\xc3\x9f\0"
|
|
|
|
"à\0" "\xc3\xa0\0"
|
|
|
|
"á\0" "\xc3\xa1\0"
|
|
|
|
"â\0" "\xc3\xa2\0"
|
|
|
|
"ã\0" "\xc3\xa3\0"
|
|
|
|
"ä\0" "\xc3\xa4\0"
|
|
|
|
"å\0" "\xc3\xa5\0"
|
|
|
|
"æ\0" "\xc3\xa6\0"
|
|
|
|
"ç\0" "\xc3\xa7\0"
|
|
|
|
"è\0" "\xc3\xa8\0"
|
|
|
|
"é\0" "\xc3\xa9\0"
|
|
|
|
"ê\0" "\xc3\xaa\0"
|
|
|
|
"ë\0" "\xc3\xab\0"
|
|
|
|
"ì\0" "\xc3\xac\0"
|
|
|
|
"í\0" "\xc3\xad\0"
|
|
|
|
"î\0" "\xc3\xae\0"
|
|
|
|
"ï\0" "\xc3\xaf\0"
|
|
|
|
"ð\0" "\xc3\xb0\0"
|
|
|
|
"ñ\0" "\xc3\xb1\0"
|
|
|
|
"ò\0" "\xc3\xb2\0"
|
|
|
|
"ó\0" "\xc3\xb3\0"
|
|
|
|
"ô\0" "\xc3\xb4\0"
|
|
|
|
"õ\0" "\xc3\xb5\0"
|
|
|
|
"ö\0" "\xc3\xb6\0"
|
|
|
|
"÷\0" "\xc3\xb7\0"
|
|
|
|
"ø\0" "\xc3\xb8\0"
|
|
|
|
"ù\0" "\xc3\xb9\0"
|
|
|
|
"ú\0" "\xc3\xba\0"
|
|
|
|
"û\0" "\xc3\xbb\0"
|
|
|
|
"ü\0" "\xc3\xbc\0"
|
|
|
|
"ý\0" "\xc3\xbd\0"
|
|
|
|
"þ\0" "\xc3\xbe\0"
|
|
|
|
"ÿ\0" "\xc3\xbf\0"
|
|
|
|
"α\0" "\xce\x91\0"
|
|
|
|
"β\0" "\xce\x92\0"
|
|
|
|
"γ\0" "\xce\x93\0"
|
|
|
|
"δ\0" "\xce\x94\0"
|
|
|
|
"ε\0" "\xce\x95\0"
|
|
|
|
"ζ\0" "\xce\x96\0"
|
|
|
|
"η\0" "\xce\x97\0"
|
|
|
|
"θ\0" "\xce\x98\0"
|
|
|
|
"ι\0" "\xce\x99\0"
|
|
|
|
"κ\0" "\xce\x9a\0"
|
|
|
|
"λ\0" "\xce\x9b\0"
|
|
|
|
"μ\0" "\xce\x9c\0"
|
|
|
|
"ν\0" "\xce\x9d\0"
|
|
|
|
"ξ\0" "\xce\x9e\0"
|
|
|
|
"ο\0" "\xce\x9f\0"
|
|
|
|
"π\0" "\xce\xa0\0"
|
|
|
|
"ρ\0" "\xce\xa1\0"
|
|
|
|
"σ\0" "\xce\xa3\0"
|
|
|
|
"τ\0" "\xce\xa4\0"
|
|
|
|
"υ\0" "\xce\xa5\0"
|
|
|
|
"φ\0" "\xce\xa6\0"
|
|
|
|
"χ\0" "\xce\xa7\0"
|
|
|
|
"ψ\0" "\xce\xa8\0"
|
|
|
|
"ω\0" "\xce\xa9\0"
|
|
|
|
"…\0" "\xe2\x80\xa6\0"
|
|
|
|
"€\0" "\xe2\x82\xac\0"
|
|
|
|
"←\0" "\xe2\x86\x90\0"
|
|
|
|
"↑\0" "\xe2\x86\x91\0"
|
|
|
|
"→\0" "\xe2\x86\x92\0"
|
|
|
|
"↓\0" "\xe2\x86\x93\0"
|
|
|
|
"↔\0" "\xe2\x86\x94\0"
|
|
|
|
"←\0" "\xe2\x87\x90\0"
|
|
|
|
"→\0" "\xe2\x87\x92\0"
|
|
|
|
"∀\0" "\xe2\x88\x80\0"
|
|
|
|
"∃\0" "\xe2\x88\x83\0"
|
|
|
|
"∇\0" "\xe2\x88\x87\0"
|
|
|
|
"∏\0" "\xe2\x88\x8f\0"
|
|
|
|
"∑\0" "\xe2\x88\x91\0"
|
|
|
|
"∧\0" "\xe2\x88\xa7\0"
|
|
|
|
"∨\0" "\xe2\x88\xa8\0"
|
|
|
|
"∫\0" "\xe2\x88\xab\0"
|
|
|
|
"≠\0" "\xe2\x89\xa0\0"
|
|
|
|
"≡\0" "\xe2\x89\xa1\0"
|
|
|
|
"⊕\0" "\xe2\x8a\x95\0"
|
|
|
|
"⊥\0" "\xe2\x8a\xa5\0"
|
|
|
|
"†\0" "\xe2\x80\xa0\0"
|
|
|
|
"‡\0" "\xe2\x80\xa1\0"
|
|
|
|
"•\0" "\xe2\x80\xa2\0"
|
2009-12-21 11:07:51 -08:00
|
|
|
;
|
|
|
|
|
2010-11-26 02:01:18 -08:00
|
|
|
EVAS_MEMPOOL(_mp_obj);
|
2009-12-21 11:07:51 -08:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Checks if a char is a whitespace.
|
|
|
|
* @param c the unicode codepoint.
|
|
|
|
* @return EINA_TRUE if the unicode codepoint is a whitespace, EINA_FALSE otherwise.
|
|
|
|
*/
|
|
|
|
static Eina_Bool
|
|
|
|
_is_white(Eina_Unicode c)
|
2005-08-08 08:41:38 -07:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* unicode list of whitespace chars
|
|
|
|
*
|
|
|
|
* 0009..000D <control-0009>..<control-000D>
|
|
|
|
* 0020 SPACE
|
|
|
|
* 0085 <control-0085>
|
|
|
|
* 00A0 NO-BREAK SPACE
|
|
|
|
* 1680 OGHAM SPACE MARK
|
|
|
|
* 180E MONGOLIAN VOWEL SEPARATOR
|
|
|
|
* 2000..200A EN QUAD..HAIR SPACE
|
|
|
|
* 2028 LINE SEPARATOR
|
|
|
|
* 2029 PARAGRAPH SEPARATOR
|
|
|
|
* 202F NARROW NO-BREAK SPACE
|
|
|
|
* 205F MEDIUM MATHEMATICAL SPACE
|
|
|
|
* 3000 IDEOGRAPHIC SPACE
|
|
|
|
*/
|
|
|
|
if (
|
2010-08-09 09:24:17 -07:00
|
|
|
(c == 0x20) ||
|
|
|
|
((c >= 0x9) && (c <= 0xd)) ||
|
|
|
|
(c == 0x85) ||
|
|
|
|
(c == 0xa0) ||
|
|
|
|
(c == 0x1680) ||
|
|
|
|
(c == 0x180e) ||
|
|
|
|
((c >= 0x2000) && (c <= 0x200a)) ||
|
|
|
|
(c == 0x2028) ||
|
|
|
|
(c == 0x2029) ||
|
|
|
|
(c == 0x202f) ||
|
|
|
|
(c == 0x205f) ||
|
|
|
|
(c == 0x3000)
|
|
|
|
)
|
2010-08-10 07:36:48 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
2005-08-08 08:41:38 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Appends the text between s and p to the main cursor of the object.
|
|
|
|
*
|
2011-04-10 00:27:07 -07:00
|
|
|
* @param cur the cursor to append to.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @param[in] s start of the string
|
|
|
|
* @param[in] p end of the string
|
|
|
|
*/
|
2010-08-12 02:31:43 -07:00
|
|
|
static void __UNUSED__
|
2011-04-10 00:27:07 -07:00
|
|
|
_append_text_run(Evas_Textblock_Cursor *cur, const char *s, const char *p)
|
2005-08-14 08:48:07 -07:00
|
|
|
{
|
|
|
|
if ((s) && (p > s))
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *ts;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
ts = alloca(p - s + 1);
|
|
|
|
strncpy(ts, s, p - s);
|
|
|
|
ts[p - s] = 0;
|
2011-04-10 00:27:07 -07:00
|
|
|
evas_textblock_cursor_text_append(cur, ts);
|
2005-08-14 08:48:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Prepends the text between s and p to the main cursor of the object.
|
|
|
|
*
|
2011-04-10 00:27:07 -07:00
|
|
|
* @param cur the cursor to prepend to.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @param[in] s start of the string
|
|
|
|
* @param[in] p end of the string
|
|
|
|
*/
|
2008-10-16 02:17:37 -07:00
|
|
|
static void
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_text_run(Evas_Textblock_Cursor *cur, const char *s, const char *p)
|
2008-10-16 02:17:37 -07:00
|
|
|
{
|
|
|
|
if ((s) && (p > s))
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *ts;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
ts = alloca(p - s + 1);
|
|
|
|
strncpy(ts, s, p - s);
|
|
|
|
ts[p - s] = 0;
|
2011-04-10 00:27:07 -07:00
|
|
|
evas_textblock_cursor_text_prepend(cur, ts);
|
2008-10-16 02:17:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns the numeric value of HEX chars for example for ch = 'A'
|
|
|
|
* the function will return 10.
|
|
|
|
*
|
|
|
|
* @param ch The HEX char.
|
|
|
|
* @return numeric value of HEX.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static int
|
|
|
|
_hex_string_get(char ch)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
if ((ch >= '0') && (ch <= '9')) return (ch - '0');
|
|
|
|
else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
|
|
|
|
else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Parses a string of one of the formas:
|
|
|
|
* 1. "#RRGGBB"
|
|
|
|
* 2. "#RRGGBBAA"
|
|
|
|
* 3. "#RGB"
|
|
|
|
* 4. "#RGBA"
|
|
|
|
* To the rgba values.
|
|
|
|
*
|
|
|
|
* @param[in] str The string to parse - NOT NULL.
|
|
|
|
* @param[out] r The Red value - NOT NULL.
|
|
|
|
* @param[out] g The Green value - NOT NULL.
|
|
|
|
* @param[out] b The Blue value - NOT NULL.
|
|
|
|
* @param[out] a The Alpha value - NOT NULL.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2006-11-28 08:14:11 -08:00
|
|
|
_format_color_parse(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
int slen;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
slen = strlen(str);
|
|
|
|
*r = *g = *b = *a = 0;
|
2005-10-15 15:02:59 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (slen == 7) /* #RRGGBB */
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
*r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
|
|
|
|
*g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
|
|
|
|
*b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
|
|
|
|
*a = 0xff;
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else if (slen == 9) /* #RRGGBBAA */
|
2005-08-16 02:25:48 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
*r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
|
|
|
|
*g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
|
|
|
|
*b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
|
|
|
|
*a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8]));
|
2005-08-16 02:25:48 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else if (slen == 4) /* #RGB */
|
2005-08-15 05:46:16 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
*r = _hex_string_get(str[1]);
|
|
|
|
*r = (*r << 4) | *r;
|
|
|
|
*g = _hex_string_get(str[2]);
|
|
|
|
*g = (*g << 4) | *g;
|
|
|
|
*b = _hex_string_get(str[3]);
|
|
|
|
*b = (*b << 4) | *b;
|
|
|
|
*a = 0xff;
|
2005-08-15 05:46:16 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else if (slen == 5) /* #RGBA */
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
*r = _hex_string_get(str[1]);
|
|
|
|
*r = (*r << 4) | *r;
|
|
|
|
*g = _hex_string_get(str[2]);
|
|
|
|
*g = (*g << 4) | *g;
|
|
|
|
*b = _hex_string_get(str[3]);
|
|
|
|
*b = (*b << 4) | *b;
|
|
|
|
*a = _hex_string_get(str[4]);
|
|
|
|
*a = (*a << 4) | *a;
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-09-30 03:18:37 -07:00
|
|
|
*r = (*r * *a) / 255;
|
|
|
|
*g = (*g * *a) / 255;
|
|
|
|
*b = (*b * *a) / 255;
|
2005-08-03 06:07:00 -07:00
|
|
|
}
|
2005-05-21 19:49:50 -07:00
|
|
|
|
2010-08-11 04:20:10 -07:00
|
|
|
/* The refcount for the formats. */
|
|
|
|
static int format_refcount = 0;
|
2010-08-10 07:36:48 -07:00
|
|
|
/* Holders for the stringshares */
|
2010-02-03 07:47:13 -08:00
|
|
|
static const char *fontstr = NULL;
|
|
|
|
static const char *font_fallbacksstr = NULL;
|
|
|
|
static const char *font_sizestr = NULL;
|
|
|
|
static const char *font_sourcestr = NULL;
|
|
|
|
static const char *colorstr = NULL;
|
|
|
|
static const char *underline_colorstr = NULL;
|
|
|
|
static const char *underline2_colorstr = NULL;
|
|
|
|
static const char *outline_colorstr = NULL;
|
|
|
|
static const char *shadow_colorstr = NULL;
|
|
|
|
static const char *glow_colorstr = NULL;
|
|
|
|
static const char *glow2_colorstr = NULL;
|
|
|
|
static const char *backing_colorstr = NULL;
|
|
|
|
static const char *strikethrough_colorstr = NULL;
|
|
|
|
static const char *alignstr = NULL;
|
|
|
|
static const char *valignstr = NULL;
|
|
|
|
static const char *wrapstr = NULL;
|
|
|
|
static const char *left_marginstr = NULL;
|
|
|
|
static const char *right_marginstr = NULL;
|
|
|
|
static const char *underlinestr = NULL;
|
|
|
|
static const char *strikethroughstr = NULL;
|
|
|
|
static const char *backingstr = NULL;
|
|
|
|
static const char *stylestr = NULL;
|
|
|
|
static const char *tabstopsstr = NULL;
|
|
|
|
static const char *linesizestr = NULL;
|
|
|
|
static const char *linerelsizestr = NULL;
|
2010-04-25 04:35:41 -07:00
|
|
|
static const char *linegapstr = NULL;
|
|
|
|
static const char *linerelgapstr = NULL;
|
|
|
|
static const char *itemstr = NULL;
|
2010-06-19 23:32:05 -07:00
|
|
|
static const char *linefillstr = NULL;
|
2011-01-30 02:45:45 -08:00
|
|
|
static const char *ellipsisstr = NULL;
|
2011-04-28 04:08:20 -07:00
|
|
|
static const char *passwordstr = NULL;
|
2006-11-28 08:14:11 -08:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Init the format strings.
|
|
|
|
*/
|
2006-11-28 08:14:11 -08:00
|
|
|
static void
|
2007-06-27 03:57:54 -07:00
|
|
|
_format_command_init(void)
|
2006-11-28 08:14:11 -08:00
|
|
|
{
|
2010-08-11 04:20:10 -07:00
|
|
|
if (format_refcount == 0)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
fontstr = eina_stringshare_add("font");
|
|
|
|
font_fallbacksstr = eina_stringshare_add("font_fallbacks");
|
|
|
|
font_sizestr = eina_stringshare_add("font_size");
|
|
|
|
font_sourcestr = eina_stringshare_add("font_source");
|
|
|
|
colorstr = eina_stringshare_add("color");
|
|
|
|
underline_colorstr = eina_stringshare_add("underline_color");
|
|
|
|
underline2_colorstr = eina_stringshare_add("underline2_color");
|
|
|
|
outline_colorstr = eina_stringshare_add("outline_color");
|
|
|
|
shadow_colorstr = eina_stringshare_add("shadow_color");
|
|
|
|
glow_colorstr = eina_stringshare_add("glow_color");
|
|
|
|
glow2_colorstr = eina_stringshare_add("glow2_color");
|
|
|
|
backing_colorstr = eina_stringshare_add("backing_color");
|
|
|
|
strikethrough_colorstr = eina_stringshare_add("strikethrough_color");
|
|
|
|
alignstr = eina_stringshare_add("align");
|
|
|
|
valignstr = eina_stringshare_add("valign");
|
|
|
|
wrapstr = eina_stringshare_add("wrap");
|
|
|
|
left_marginstr = eina_stringshare_add("left_margin");
|
|
|
|
right_marginstr = eina_stringshare_add("right_margin");
|
|
|
|
underlinestr = eina_stringshare_add("underline");
|
|
|
|
strikethroughstr = eina_stringshare_add("strikethrough");
|
|
|
|
backingstr = eina_stringshare_add("backing");
|
|
|
|
stylestr = eina_stringshare_add("style");
|
|
|
|
tabstopsstr = eina_stringshare_add("tabstops");
|
|
|
|
linesizestr = eina_stringshare_add("linesize");
|
|
|
|
linerelsizestr = eina_stringshare_add("linerelsize");
|
|
|
|
linegapstr = eina_stringshare_add("linegap");
|
|
|
|
linerelgapstr = eina_stringshare_add("linerelgap");
|
|
|
|
itemstr = eina_stringshare_add("item");
|
|
|
|
linefillstr = eina_stringshare_add("linefill");
|
2011-01-30 02:45:45 -08:00
|
|
|
ellipsisstr = eina_stringshare_add("ellipsis");
|
2011-04-28 04:08:20 -07:00
|
|
|
passwordstr = eina_stringshare_add("password");
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-11 04:20:10 -07:00
|
|
|
format_refcount++;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Shutdown the format strings.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2007-06-27 03:57:54 -07:00
|
|
|
_format_command_shutdown(void)
|
2006-11-28 08:14:11 -08:00
|
|
|
{
|
2010-08-11 04:20:10 -07:00
|
|
|
if (--format_refcount > 0) return;
|
|
|
|
|
2008-10-15 07:38:34 -07:00
|
|
|
eina_stringshare_del(fontstr);
|
|
|
|
eina_stringshare_del(font_fallbacksstr);
|
|
|
|
eina_stringshare_del(font_sizestr);
|
|
|
|
eina_stringshare_del(font_sourcestr);
|
|
|
|
eina_stringshare_del(colorstr);
|
|
|
|
eina_stringshare_del(underline_colorstr);
|
|
|
|
eina_stringshare_del(underline2_colorstr);
|
|
|
|
eina_stringshare_del(outline_colorstr);
|
|
|
|
eina_stringshare_del(shadow_colorstr);
|
|
|
|
eina_stringshare_del(glow_colorstr);
|
|
|
|
eina_stringshare_del(glow2_colorstr);
|
|
|
|
eina_stringshare_del(backing_colorstr);
|
|
|
|
eina_stringshare_del(strikethrough_colorstr);
|
|
|
|
eina_stringshare_del(alignstr);
|
|
|
|
eina_stringshare_del(valignstr);
|
|
|
|
eina_stringshare_del(wrapstr);
|
|
|
|
eina_stringshare_del(left_marginstr);
|
|
|
|
eina_stringshare_del(right_marginstr);
|
|
|
|
eina_stringshare_del(underlinestr);
|
|
|
|
eina_stringshare_del(strikethroughstr);
|
|
|
|
eina_stringshare_del(backingstr);
|
|
|
|
eina_stringshare_del(stylestr);
|
|
|
|
eina_stringshare_del(tabstopsstr);
|
2009-09-03 20:53:18 -07:00
|
|
|
eina_stringshare_del(linesizestr);
|
|
|
|
eina_stringshare_del(linerelsizestr);
|
2010-04-25 04:35:41 -07:00
|
|
|
eina_stringshare_del(linegapstr);
|
|
|
|
eina_stringshare_del(linerelgapstr);
|
|
|
|
eina_stringshare_del(itemstr);
|
2010-06-19 23:32:05 -07:00
|
|
|
eina_stringshare_del(linefillstr);
|
2011-01-30 02:45:45 -08:00
|
|
|
eina_stringshare_del(ellipsisstr);
|
2011-04-28 04:08:20 -07:00
|
|
|
eina_stringshare_del(passwordstr);
|
2006-11-28 08:14:11 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Copies str to dst while removing the \\ char, i.e unescape the escape sequences.
|
|
|
|
*
|
|
|
|
* @param[out] dst the destination string - Should not be NULL.
|
|
|
|
* @param[in] src the source string - Should not be NULL.
|
|
|
|
*/
|
2006-11-28 12:30:48 -08:00
|
|
|
static void
|
|
|
|
_format_clean_param(char *dst, const char *src)
|
|
|
|
{
|
|
|
|
const char *ss;
|
|
|
|
char *ds;
|
|
|
|
|
|
|
|
ds = dst;
|
|
|
|
for (ss = src; *ss; ss++, ds++)
|
|
|
|
{
|
|
|
|
if ((*ss == '\\') && *(ss + 1)) ss++;
|
|
|
|
*ds = *ss;
|
|
|
|
}
|
|
|
|
*ds = 0;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Parses the cmd and parameter and adds the parsed format to fmt.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - should not be NULL.
|
|
|
|
* @param fmt The format to populate - should not be NULL.
|
2010-09-07 20:51:24 -07:00
|
|
|
* @param[in] cmd the command to process, should be stringshared.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @param[in] param the parameter of the command.
|
|
|
|
*/
|
2006-11-28 08:14:11 -08:00
|
|
|
static void
|
|
|
|
_format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *cmd, const char *param)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
int new_font = 0;
|
2011-04-11 05:05:59 -07:00
|
|
|
int len;
|
2006-11-28 12:30:48 -08:00
|
|
|
char *tmp_param;
|
|
|
|
|
2011-04-11 05:05:59 -07:00
|
|
|
len = strlen(param);
|
|
|
|
tmp_param = alloca(len + 1);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2006-11-28 12:30:48 -08:00
|
|
|
_format_clean_param(tmp_param, param);
|
2006-11-28 08:14:11 -08:00
|
|
|
if (cmd == fontstr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if ((!fmt->font.name) ||
|
|
|
|
((fmt->font.name) && (strcmp(fmt->font.name, tmp_param))))
|
|
|
|
{
|
|
|
|
if (fmt->font.name) eina_stringshare_del(fmt->font.name);
|
|
|
|
fmt->font.name = eina_stringshare_add(tmp_param);
|
|
|
|
new_font = 1;
|
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == font_fallbacksstr)
|
2005-09-12 01:57:38 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if ((!fmt->font.fallbacks) ||
|
|
|
|
((fmt->font.fallbacks) && (strcmp(fmt->font.fallbacks, tmp_param))))
|
|
|
|
{
|
|
|
|
/* policy - when we say "fallbacks" do we prepend and use prior
|
|
|
|
* fallbacks... or should we replace. for now we replace
|
|
|
|
*/
|
|
|
|
if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
|
|
|
|
fmt->font.fallbacks = eina_stringshare_add(tmp_param);
|
|
|
|
new_font = 1;
|
|
|
|
}
|
2005-09-12 01:57:38 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == font_sizestr)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
int v;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
v = atoi(tmp_param);
|
|
|
|
if (v != fmt->font.size)
|
|
|
|
{
|
|
|
|
fmt->font.size = v;
|
|
|
|
new_font = 1;
|
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == font_sourcestr)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if ((!fmt->font.source) ||
|
|
|
|
((fmt->font.source) && (strcmp(fmt->font.source, tmp_param))))
|
|
|
|
{
|
|
|
|
if (fmt->font.source) eina_stringshare_del(fmt->font.source);
|
|
|
|
fmt->font.source = eina_stringshare_add(tmp_param);
|
|
|
|
new_font = 1;
|
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.normal.r), &(fmt->color.normal.g),
|
|
|
|
&(fmt->color.normal.b), &(fmt->color.normal.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == underline_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.underline.r), &(fmt->color.underline.g),
|
|
|
|
&(fmt->color.underline.b), &(fmt->color.underline.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == underline2_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.underline2.r), &(fmt->color.underline2.g),
|
|
|
|
&(fmt->color.underline2.b), &(fmt->color.underline2.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == outline_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.outline.r), &(fmt->color.outline.g),
|
|
|
|
&(fmt->color.outline.b), &(fmt->color.outline.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == shadow_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.shadow.r), &(fmt->color.shadow.g),
|
|
|
|
&(fmt->color.shadow.b), &(fmt->color.shadow.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == glow_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.glow.r), &(fmt->color.glow.g),
|
|
|
|
&(fmt->color.glow.b), &(fmt->color.glow.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == glow2_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.glow2.r), &(fmt->color.glow2.g),
|
|
|
|
&(fmt->color.glow2.b), &(fmt->color.glow2.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == backing_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.backing.r), &(fmt->color.backing.g),
|
|
|
|
&(fmt->color.backing.b), &(fmt->color.backing.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == strikethrough_colorstr)
|
2008-07-21 04:20:19 -07:00
|
|
|
_format_color_parse(tmp_param,
|
2010-08-09 09:24:17 -07:00
|
|
|
&(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g),
|
|
|
|
&(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a));
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == alignstr)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2010-08-11 00:46:37 -07:00
|
|
|
if (!strcmp(tmp_param, "auto"))
|
|
|
|
{
|
|
|
|
fmt->halign_auto = EINA_TRUE;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
else
|
|
|
|
{
|
2010-08-11 00:46:37 -07:00
|
|
|
if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5;
|
|
|
|
else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5;
|
|
|
|
else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0;
|
|
|
|
else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0;
|
|
|
|
else
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-11 00:46:37 -07:00
|
|
|
char *endptr = NULL;
|
|
|
|
double val = strtod(tmp_param, &endptr);
|
|
|
|
if (endptr)
|
|
|
|
{
|
|
|
|
while (*endptr && _is_white(*endptr))
|
|
|
|
endptr++;
|
|
|
|
if (*endptr == '%')
|
|
|
|
val /= 100.0;
|
|
|
|
}
|
|
|
|
fmt->halign = val;
|
|
|
|
if (fmt->halign < 0.0) fmt->halign = 0.0;
|
|
|
|
else if (fmt->halign > 1.0) fmt->halign = 1.0;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-11 00:46:37 -07:00
|
|
|
fmt->halign_auto = EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == valignstr)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2008-07-21 04:20:19 -07:00
|
|
|
if (!strcmp(tmp_param, "top")) fmt->valign = 0.0;
|
2010-08-09 09:24:17 -07:00
|
|
|
else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5;
|
|
|
|
else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5;
|
|
|
|
else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0;
|
|
|
|
else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0;
|
|
|
|
else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *endptr = NULL;
|
|
|
|
double val = strtod(tmp_param, &endptr);
|
|
|
|
if (endptr)
|
|
|
|
{
|
|
|
|
while (*endptr && _is_white(*endptr))
|
|
|
|
endptr++;
|
|
|
|
if (*endptr == '%')
|
|
|
|
val /= 100.0;
|
|
|
|
}
|
|
|
|
fmt->valign = val;
|
|
|
|
if (fmt->valign < 0.0) fmt->valign = 0.0;
|
|
|
|
else if (fmt->valign > 1.0) fmt->valign = 1.0;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == wrapstr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "word"))
|
|
|
|
{
|
|
|
|
fmt->wrap_word = 1;
|
2011-01-30 02:44:03 -08:00
|
|
|
fmt->wrap_char = fmt->wrap_mixed = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else if (!strcmp(tmp_param, "char"))
|
|
|
|
{
|
2011-01-30 02:44:03 -08:00
|
|
|
fmt->wrap_word = fmt->wrap_mixed = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt->wrap_char = 1;
|
|
|
|
}
|
2011-01-30 02:44:03 -08:00
|
|
|
else if (!strcmp(tmp_param, "mixed"))
|
|
|
|
{
|
|
|
|
fmt->wrap_word = fmt->wrap_char = 0;
|
|
|
|
fmt->wrap_mixed = 1;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:44:03 -08:00
|
|
|
fmt->wrap_word = fmt->wrap_mixed = fmt->wrap_char = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == left_marginstr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "reset"))
|
|
|
|
fmt->margin.l = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tmp_param[0] == '+')
|
|
|
|
fmt->margin.l += atoi(&(tmp_param[1]));
|
|
|
|
else if (tmp_param[0] == '-')
|
|
|
|
fmt->margin.l -= atoi(&(tmp_param[1]));
|
|
|
|
else
|
|
|
|
fmt->margin.l = atoi(tmp_param);
|
|
|
|
if (fmt->margin.l < 0) fmt->margin.l = 0;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == right_marginstr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "reset"))
|
|
|
|
fmt->margin.r = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tmp_param[0] == '+')
|
|
|
|
fmt->margin.r += atoi(&(tmp_param[1]));
|
|
|
|
else if (tmp_param[0] == '-')
|
|
|
|
fmt->margin.r -= atoi(&(tmp_param[1]));
|
|
|
|
else
|
|
|
|
fmt->margin.r = atoi(tmp_param);
|
|
|
|
if (fmt->margin.r < 0) fmt->margin.r = 0;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == underlinestr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "off"))
|
|
|
|
{
|
|
|
|
fmt->underline = 0;
|
|
|
|
fmt->underline2 = 0;
|
|
|
|
}
|
|
|
|
else if ((!strcmp(tmp_param, "on")) ||
|
|
|
|
(!strcmp(tmp_param, "single")))
|
|
|
|
{
|
|
|
|
fmt->underline = 1;
|
|
|
|
fmt->underline2 = 0;
|
|
|
|
}
|
|
|
|
else if (!strcmp(tmp_param, "double"))
|
|
|
|
{
|
|
|
|
fmt->underline = 1;
|
|
|
|
fmt->underline2 = 1;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == strikethroughstr)
|
2005-08-18 08:59:42 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "off"))
|
|
|
|
fmt->strikethrough = 0;
|
|
|
|
else if (!strcmp(tmp_param, "on"))
|
|
|
|
fmt->strikethrough = 1;
|
2005-08-18 08:59:42 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == backingstr)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!strcmp(tmp_param, "off"))
|
|
|
|
fmt->backing = 0;
|
|
|
|
else if (!strcmp(tmp_param, "on"))
|
|
|
|
fmt->backing = 1;
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == stylestr)
|
2005-08-18 08:59:42 -07:00
|
|
|
{
|
2011-04-11 05:05:59 -07:00
|
|
|
char *p1, *p2, *p, *pp;
|
2011-04-13 02:29:45 -07:00
|
|
|
|
2011-04-11 05:05:59 -07:00
|
|
|
p1 = alloca(len + 1);
|
|
|
|
*p1 = 0;
|
|
|
|
p2 = alloca(len + 1);
|
|
|
|
*p2 = 0;
|
|
|
|
/* no comma */
|
|
|
|
if (!strstr(tmp_param, ",")) p1 = tmp_param;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* split string "str1,str2" into p1 and p2 (if we have more than
|
|
|
|
* 1 str2 eg "str1,str2,str3,str4" then we don't care. p2 just
|
|
|
|
* ends up being the last one as right now it's only valid to have
|
|
|
|
* 1 comma and 2 strings */
|
|
|
|
pp = p1;
|
|
|
|
for (p = tmp_param; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p == ',')
|
|
|
|
{
|
|
|
|
*pp = 0;
|
|
|
|
pp = p2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*pp = *p;
|
|
|
|
pp++;
|
|
|
|
}
|
|
|
|
*pp = 0;
|
|
|
|
}
|
|
|
|
if (!strcmp(p1, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
|
|
|
|
else if (!strcmp(p1, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
|
|
|
|
else if (!strcmp(p1, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
|
|
|
|
else if (!strcmp(p1, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW;
|
|
|
|
else if (!strcmp(p1, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE;
|
|
|
|
else if (!strcmp(p1, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
|
|
|
|
else if (!strcmp(p1, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
|
|
|
|
else if (!strcmp(p1, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
|
|
|
|
else if (!strcmp(p1, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW;
|
|
|
|
else if (!strcmp(p1, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW;
|
|
|
|
else if (!strcmp(p1, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW;
|
|
|
|
else if (!strcmp(p1, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
|
|
|
|
else fmt->style = EVAS_TEXT_STYLE_PLAIN;
|
|
|
|
|
|
|
|
if (*p2)
|
|
|
|
{
|
|
|
|
if (!strcmp(p2, "bottom_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
|
|
|
|
else if (!strcmp(p2, "bottom")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM);
|
|
|
|
else if (!strcmp(p2, "bottom_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT);
|
|
|
|
else if (!strcmp(p2, "left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT);
|
|
|
|
else if (!strcmp(p2, "top_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT);
|
|
|
|
else if (!strcmp(p2, "top")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP);
|
|
|
|
else if (!strcmp(p2, "top_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT);
|
|
|
|
else if (!strcmp(p2, "right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT);
|
|
|
|
else EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
|
|
|
|
}
|
2005-08-18 08:59:42 -07:00
|
|
|
}
|
2006-11-28 08:14:11 -08:00
|
|
|
else if (cmd == tabstopsstr)
|
2005-08-16 02:25:48 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt->tabstops = atoi(tmp_param);
|
|
|
|
if (fmt->tabstops < 1) fmt->tabstops = 1;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2009-09-03 20:53:18 -07:00
|
|
|
else if (cmd == linesizestr)
|
|
|
|
{
|
|
|
|
fmt->linesize = atoi(tmp_param);
|
|
|
|
fmt->linerelsize = 0.0;
|
|
|
|
}
|
|
|
|
else if (cmd == linerelsizestr)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *endptr = NULL;
|
|
|
|
double val = strtod(tmp_param, &endptr);
|
|
|
|
if (endptr)
|
|
|
|
{
|
|
|
|
while (*endptr && _is_white(*endptr))
|
|
|
|
endptr++;
|
|
|
|
if (*endptr == '%')
|
|
|
|
{
|
|
|
|
fmt->linerelsize = val / 100.0;
|
|
|
|
fmt->linesize = 0;
|
|
|
|
if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0;
|
|
|
|
}
|
2009-09-03 20:53:18 -07:00
|
|
|
}
|
|
|
|
}
|
2010-04-25 04:35:41 -07:00
|
|
|
else if (cmd == linegapstr)
|
2010-04-12 01:23:53 -07:00
|
|
|
{
|
|
|
|
fmt->linegap = atoi(tmp_param);
|
|
|
|
fmt->linerelgap = 0.0;
|
|
|
|
}
|
2010-04-25 04:35:41 -07:00
|
|
|
else if (cmd == linerelgapstr)
|
2010-04-12 01:23:53 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *endptr = NULL;
|
|
|
|
double val = strtod(tmp_param, &endptr);
|
|
|
|
if (endptr)
|
|
|
|
{
|
|
|
|
while (*endptr && _is_white(*endptr))
|
|
|
|
endptr++;
|
|
|
|
if (*endptr == '%')
|
|
|
|
{
|
|
|
|
fmt->linerelgap = val / 100.0;
|
|
|
|
fmt->linegap = 0;
|
|
|
|
if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0;
|
|
|
|
}
|
2010-04-12 01:23:53 -07:00
|
|
|
}
|
|
|
|
}
|
2010-06-19 23:32:05 -07:00
|
|
|
else if (cmd == itemstr)
|
|
|
|
{
|
|
|
|
// itemstr == replacement object items in textblock - inline imges
|
|
|
|
// for example
|
|
|
|
}
|
|
|
|
else if (cmd == linefillstr)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *endptr = NULL;
|
|
|
|
double val = strtod(tmp_param, &endptr);
|
|
|
|
if (endptr)
|
|
|
|
{
|
|
|
|
while (*endptr && _is_white(*endptr))
|
|
|
|
endptr++;
|
|
|
|
if (*endptr == '%')
|
|
|
|
{
|
|
|
|
fmt->linefill = val / 100.0;
|
|
|
|
if (fmt->linefill < 0.0) fmt->linefill = 0.0;
|
|
|
|
}
|
2010-06-19 23:32:05 -07:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:45:45 -08:00
|
|
|
else if (cmd == ellipsisstr)
|
|
|
|
{
|
|
|
|
char *endptr = NULL;
|
|
|
|
fmt->ellipsis = strtod(tmp_param, &endptr);
|
|
|
|
if ((fmt->ellipsis < 0.0) || (fmt->ellipsis > 1.0))
|
|
|
|
fmt->ellipsis = -1.0;
|
2011-03-30 03:38:02 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
o->have_ellipsis = 1;
|
|
|
|
}
|
2011-01-30 02:45:45 -08:00
|
|
|
}
|
2011-04-28 04:08:20 -07:00
|
|
|
else if (cmd == passwordstr)
|
|
|
|
{
|
|
|
|
if (!strcmp(tmp_param, "off"))
|
|
|
|
fmt->password = 0;
|
|
|
|
else if (!strcmp(tmp_param, "on"))
|
|
|
|
fmt->password = 1;
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (new_font)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
void *of;
|
|
|
|
char *buf = NULL;
|
2005-09-12 01:57:38 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
of = fmt->font.font;
|
|
|
|
if ((fmt->font.name) && (fmt->font.fallbacks))
|
|
|
|
{
|
|
|
|
buf = malloc(strlen(fmt->font.name) + 1 + strlen(fmt->font.fallbacks) + 1);
|
|
|
|
strcpy(buf, fmt->font.name);
|
|
|
|
strcat(buf, ",");
|
|
|
|
strcat(buf, fmt->font.fallbacks);
|
|
|
|
}
|
|
|
|
else if (fmt->font.name)
|
|
|
|
buf = strdup(fmt->font.name);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt->font.font = evas_font_load(obj->layer->evas,
|
|
|
|
buf, fmt->font.source,
|
|
|
|
(int)(((double)fmt->font.size) * obj->cur.scale));
|
|
|
|
if (buf) free(buf);
|
|
|
|
if (of) evas_font_free(obj->layer->evas, of);
|
2005-08-16 02:25:48 -07:00
|
|
|
}
|
2005-08-03 06:07:00 -07:00
|
|
|
}
|
2005-05-21 19:49:50 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns #EINA_TRUE if the item is a format parameter, #EINA_FALSE otherwise.
|
|
|
|
*
|
|
|
|
* @param[in] item the item to check - Not NULL.
|
|
|
|
*/
|
|
|
|
static Eina_Bool
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_is_param(const char *item)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2010-08-10 07:36:48 -07:00
|
|
|
if (strchr(item, '=')) return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
2005-02-06 18:12:36 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Parse the format item and populate key and val with the stringshares that
|
|
|
|
* corrospond to the formats parsed.
|
|
|
|
* It expects item to be of the structure:
|
|
|
|
* "key=val"
|
|
|
|
*
|
|
|
|
* @param[in] item the item to parse - Not NULL.
|
|
|
|
* @param[out] key where to store the key at - Not NULL.
|
|
|
|
* @param[out] val where to store the value at - Not NULL.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2010-08-12 02:31:43 -07:00
|
|
|
_format_param_parse(const char *item, const char **key, const char **val)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2010-08-12 02:31:43 -07:00
|
|
|
const char *equal, *end;
|
|
|
|
|
|
|
|
equal = strchr(item, '=');
|
|
|
|
*key = eina_stringshare_add_length(item, equal - item);
|
|
|
|
equal++; /* Advance after the '=' */
|
2010-08-09 09:24:17 -07:00
|
|
|
/* Null terminate before the spaces */
|
2010-08-12 02:31:43 -07:00
|
|
|
end = strchr(equal, ' ');
|
|
|
|
if (end)
|
|
|
|
{
|
|
|
|
*val = eina_stringshare_add_length(equal, end - equal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*val = eina_stringshare_add(equal);
|
|
|
|
}
|
2005-01-08 04:47:36 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* FIXME: comment.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static const char *
|
|
|
|
_format_parse(const char **s)
|
2005-02-16 05:57:41 -08:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *p, *item;
|
|
|
|
const char *s1 = NULL, *s2 = NULL;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
p = *s;
|
|
|
|
if (*p == 0) return NULL;
|
|
|
|
for (;;)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!s1)
|
|
|
|
{
|
|
|
|
if (*p != ' ') s1 = p;
|
|
|
|
if (*p == 0) break;
|
|
|
|
}
|
|
|
|
else if (!s2)
|
|
|
|
{
|
|
|
|
if ((p > *s) && (p[-1] != '\\'))
|
|
|
|
{
|
|
|
|
if (*p == ' ') s2 = p;
|
|
|
|
}
|
|
|
|
if (*p == 0) s2 = p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
if (s1 && s2)
|
|
|
|
{
|
|
|
|
item = s1;
|
2006-11-28 12:30:48 -08:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
*s = s2;
|
|
|
|
return item;
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
*s = p;
|
2005-08-03 06:07:00 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-21 19:49:50 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Parse the format str and populate fmt with the formats found.
|
|
|
|
*
|
|
|
|
* @param obj The evas object - Not NULL.
|
|
|
|
* @param[out] fmt The format to populate - Not NULL.
|
|
|
|
* @param[in] str the string to parse.- Not NULL.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *str)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *s;
|
|
|
|
const char *item;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
s = str;
|
2005-10-15 15:02:59 -07:00
|
|
|
|
2006-05-11 16:46:54 -07:00
|
|
|
/* get rid of anything +s or -s off the start of the string */
|
2005-10-15 15:02:59 -07:00
|
|
|
while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
while ((item = _format_parse(&s)))
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (_format_is_param(item))
|
|
|
|
{
|
|
|
|
const char *key = NULL, *val = NULL;
|
|
|
|
|
2010-08-12 02:35:53 -07:00
|
|
|
_format_param_parse(item, &key, &val);
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_command(obj, fmt, key, val);
|
|
|
|
eina_stringshare_del(key);
|
|
|
|
eina_stringshare_del(val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* immediate - not handled here */
|
|
|
|
}
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Duplicate a format and return the duplicate.
|
|
|
|
*
|
|
|
|
* @param obj The evas object - Not NULL.
|
|
|
|
* @param[in] fmt The format to duplicate - Not NULL.
|
|
|
|
* @return the copy of the format.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static Evas_Object_Textblock_Format *
|
2010-08-10 07:36:48 -07:00
|
|
|
_format_dup(Evas_Object *obj, const Evas_Object_Textblock_Format *fmt)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format *fmt2;
|
2005-09-12 01:57:38 -07:00
|
|
|
char *buf = NULL;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
fmt2 = calloc(1, sizeof(Evas_Object_Textblock_Format));
|
|
|
|
memcpy(fmt2, fmt, sizeof(Evas_Object_Textblock_Format));
|
|
|
|
fmt2->ref = 1;
|
2008-10-15 07:38:34 -07:00
|
|
|
if (fmt->font.name) fmt2->font.name = eina_stringshare_add(fmt->font.name);
|
|
|
|
if (fmt->font.fallbacks) fmt2->font.fallbacks = eina_stringshare_add(fmt->font.fallbacks);
|
|
|
|
if (fmt->font.source) fmt2->font.source = eina_stringshare_add(fmt->font.source);
|
2005-09-12 01:57:38 -07:00
|
|
|
|
|
|
|
if ((fmt2->font.name) && (fmt2->font.fallbacks))
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
buf = malloc(strlen(fmt2->font.name) + 1 + strlen(fmt2->font.fallbacks) + 1);
|
|
|
|
strcpy(buf, fmt2->font.name);
|
|
|
|
strcat(buf, ",");
|
|
|
|
strcat(buf, fmt2->font.fallbacks);
|
2005-09-12 01:57:38 -07:00
|
|
|
}
|
|
|
|
else if (fmt2->font.name)
|
|
|
|
buf = strdup(fmt2->font.name);
|
2009-09-03 22:13:19 -07:00
|
|
|
fmt2->font.font = evas_font_load(obj->layer->evas,
|
2010-08-09 09:24:17 -07:00
|
|
|
buf, fmt2->font.source,
|
|
|
|
(int)(((double)fmt2->font.size) * obj->cur.scale));
|
2005-09-12 01:57:38 -07:00
|
|
|
if (buf) free(buf);
|
2005-08-20 01:01:59 -07:00
|
|
|
return fmt2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @typedef Ctxt
|
|
|
|
*
|
|
|
|
* A pack of information that needed to be passed around in the layout engine,
|
|
|
|
* packed for easier access.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
typedef struct _Ctxt Ctxt;
|
|
|
|
|
|
|
|
struct _Ctxt
|
|
|
|
{
|
|
|
|
Evas_Object *obj;
|
|
|
|
Evas_Object_Textblock *o;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Paragraph *paragraphs;
|
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
|
|
|
|
2008-10-21 09:31:05 -07:00
|
|
|
Eina_List *format_stack;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
int x, y;
|
|
|
|
int w, h;
|
|
|
|
int wmax, hmax;
|
2010-03-04 08:22:28 -08:00
|
|
|
int maxascent, maxdescent;
|
2005-08-20 01:01:59 -07:00
|
|
|
int marginl, marginr;
|
|
|
|
int line_no;
|
|
|
|
int underline_extend;
|
|
|
|
int have_underline, have_underline2;
|
2011-03-29 07:14:29 -07:00
|
|
|
double align, valign;
|
2011-04-03 02:14:03 -07:00
|
|
|
Eina_Bool align_auto : 1;
|
|
|
|
Eina_Bool calc_only : 1;
|
2011-04-07 04:24:15 -07:00
|
|
|
Eina_Bool width_changed : 1;
|
2005-08-20 01:01:59 -07:00
|
|
|
};
|
|
|
|
|
2011-02-14 01:37:49 -08:00
|
|
|
static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, Eina_List *rel);
|
2011-02-01 04:17:52 -08:00
|
|
|
static void _text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti);
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Adjust the ascent/descent of the format and context.
|
|
|
|
*
|
|
|
|
* @param c The context to work on - Not NUL.
|
|
|
|
* @param fmt The format to adjust - NOT NULL.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2010-03-04 08:22:28 -08:00
|
|
|
_layout_format_ascent_descent_adjust(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
int ascent, descent;
|
2005-09-14 02:01:26 -07:00
|
|
|
|
|
|
|
if (fmt->font.font)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
// ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font);
|
|
|
|
// descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font);
|
2010-05-01 07:08:14 -07:00
|
|
|
ascent = c->ENFN->font_ascent_get(c->ENDT, fmt->font.font);
|
2010-08-09 09:24:17 -07:00
|
|
|
descent = c->ENFN->font_descent_get(c->ENDT, fmt->font.font);
|
2009-09-03 20:53:18 -07:00
|
|
|
if (fmt->linesize > 0)
|
|
|
|
{
|
2010-03-06 23:29:26 -08:00
|
|
|
if ((ascent + descent) < fmt->linesize)
|
2009-09-03 20:53:18 -07:00
|
|
|
{
|
|
|
|
ascent = ((fmt->linesize * ascent) / (ascent + descent));
|
|
|
|
descent = fmt->linesize - ascent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (fmt->linerelsize > 0.0)
|
|
|
|
{
|
2010-08-22 05:26:40 -07:00
|
|
|
descent = descent * fmt->linerelsize;
|
2009-09-03 20:53:18 -07:00
|
|
|
ascent = ascent * fmt->linerelsize;
|
|
|
|
}
|
2010-04-12 01:23:53 -07:00
|
|
|
c->maxdescent += fmt->linegap;
|
|
|
|
c->maxdescent += ((ascent + descent) * fmt->linerelgap);
|
2010-08-09 09:24:17 -07:00
|
|
|
if (c->maxascent < ascent) c->maxascent = ascent;
|
|
|
|
if (c->maxdescent < descent) c->maxdescent = descent;
|
2010-06-19 23:32:05 -07:00
|
|
|
if (fmt->linefill > 0.0)
|
|
|
|
{
|
|
|
|
int dh;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-06-19 23:32:05 -07:00
|
|
|
dh = c->obj->cur.geometry.h - (c->maxascent + c->maxdescent);
|
|
|
|
if (dh < 0) dh = 0;
|
|
|
|
dh = fmt->linefill * dh;
|
|
|
|
c->maxdescent += dh / 2;
|
|
|
|
c->maxascent += dh - (dh / 2);
|
|
|
|
// FIXME: set flag that says "if heigh changes - reformat"
|
|
|
|
}
|
2005-09-14 02:01:26 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create a new line using the info from the format and update the format
|
|
|
|
* and context.
|
|
|
|
*
|
|
|
|
* @param c The context to work on - Not NULL.
|
|
|
|
* @param fmt The format to use info from - NOT NULL.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
|
|
|
_layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
|
|
|
{
|
|
|
|
c->ln = calloc(1, sizeof(Evas_Object_Textblock_Line));
|
|
|
|
c->align = fmt->halign;
|
2010-08-11 00:23:48 -07:00
|
|
|
c->align_auto = fmt->halign_auto;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->marginl = fmt->margin.l;
|
|
|
|
c->marginr = fmt->margin.r;
|
2010-08-09 09:24:17 -07:00
|
|
|
c->par->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->par->lines), EINA_INLIST_GET(c->ln));
|
2005-08-20 01:01:59 -07:00
|
|
|
c->x = 0;
|
2010-03-04 08:22:28 -08:00
|
|
|
c->maxascent = c->maxdescent = 0;
|
2005-08-27 23:41:54 -07:00
|
|
|
c->ln->line_no = -1;
|
2011-01-30 02:39:47 -08:00
|
|
|
c->ln->par = c->par;
|
2010-03-04 08:22:28 -08:00
|
|
|
_layout_format_ascent_descent_adjust(c, fmt);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create a new layout paragraph.
|
2011-04-07 04:24:15 -07:00
|
|
|
* If c->par is not NULL, the paragraph is appended/prepended according
|
|
|
|
* to the append parameter. If it is NULL, the paragraph is appended at
|
|
|
|
* the end of the list.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param c The context to work on - Not NULL.
|
2011-04-07 04:24:15 -07:00
|
|
|
* @param n the associated text node
|
|
|
|
* @param append true to append, false to prpend.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
2011-04-07 04:24:15 -07:00
|
|
|
_layout_paragraph_new(Ctxt *c, Evas_Object_Textblock_Node_Text *n,
|
|
|
|
Eina_Bool append)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2011-04-07 04:24:15 -07:00
|
|
|
Evas_Object_Textblock_Paragraph *rel_par = c->par;
|
2010-08-09 09:24:17 -07:00
|
|
|
c->par = calloc(1, sizeof(Evas_Object_Textblock_Paragraph));
|
2011-04-07 04:24:15 -07:00
|
|
|
if (append || !rel_par)
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_append_relative(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->par),
|
|
|
|
EINA_INLIST_GET(rel_par));
|
|
|
|
else
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_prepend_relative(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->par),
|
|
|
|
EINA_INLIST_GET(rel_par));
|
|
|
|
|
2011-01-30 02:39:47 -08:00
|
|
|
c->ln = NULL;
|
2011-01-30 02:39:52 -08:00
|
|
|
c->par->text_node = n;
|
2011-04-14 05:13:20 -07:00
|
|
|
if (n)
|
|
|
|
n->par = c->par;
|
2011-01-30 02:39:47 -08:00
|
|
|
c->par->line_no = -1;
|
2011-04-11 06:44:01 -07:00
|
|
|
c->par->visible = 1;
|
2011-04-14 05:13:20 -07:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
c->par->bidi_props = evas_bidi_paragraph_props_new();
|
|
|
|
#endif
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2011-04-14 05:13:20 -07:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Update bidi paragraph props.
|
|
|
|
*
|
|
|
|
* @param par The paragraph to update
|
|
|
|
*/
|
|
|
|
static inline void
|
2011-04-14 08:34:01 -07:00
|
|
|
_layout_update_bidi_props(const Evas_Object_Textblock *o,
|
|
|
|
Evas_Object_Textblock_Paragraph *par)
|
2011-04-14 05:13:20 -07:00
|
|
|
{
|
|
|
|
if (par->text_node)
|
|
|
|
{
|
2011-04-14 08:34:01 -07:00
|
|
|
const Eina_Unicode *text;
|
|
|
|
int *segment_idxs = NULL;
|
|
|
|
text = eina_ustrbuf_string_get(par->text_node->unicode);
|
|
|
|
|
|
|
|
if (o->bidi_delimiters)
|
|
|
|
segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
|
|
|
|
|
2011-04-14 05:13:20 -07:00
|
|
|
evas_bidi_paragraph_props_unref(par->bidi_props);
|
2011-04-14 08:34:01 -07:00
|
|
|
par->bidi_props = evas_bidi_paragraph_props_get(text,
|
2011-04-14 05:13:20 -07:00
|
|
|
eina_ustrbuf_length_get(par->text_node->unicode),
|
2011-04-14 08:34:01 -07:00
|
|
|
segment_idxs);
|
|
|
|
if (segment_idxs) free(segment_idxs);
|
2011-04-14 05:13:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-01-30 02:41:42 -08:00
|
|
|
* Free the visual lines in the paragraph (logical items are kept)
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
2011-01-30 02:41:42 -08:00
|
|
|
_paragraph_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
while (par->lines)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Line *ln;
|
|
|
|
|
|
|
|
ln = (Evas_Object_Textblock_Line *) par->lines;
|
|
|
|
par->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(par->lines), EINA_INLIST_GET(par->lines));
|
|
|
|
_line_free(obj, ln);
|
|
|
|
}
|
2011-01-30 02:41:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Free the layout paragraph and all of it's lines and logical items.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
|
|
|
{
|
|
|
|
_paragraph_clear(obj, par);
|
2011-01-30 02:40:14 -08:00
|
|
|
|
|
|
|
{
|
|
|
|
Eina_List *i, *i_prev;
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
EINA_LIST_FOREACH_SAFE(par->logical_items, i, i_prev, it)
|
|
|
|
{
|
|
|
|
_item_free(obj, NULL, it);
|
|
|
|
}
|
|
|
|
eina_list_free(par->logical_items);
|
|
|
|
}
|
2011-04-14 05:13:20 -07:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
if (par->bidi_props)
|
|
|
|
evas_bidi_paragraph_props_unref(par->bidi_props);
|
|
|
|
#endif
|
2011-04-17 01:38:29 -07:00
|
|
|
/* If we are the active par of the text node, set to NULL */
|
|
|
|
if (par->text_node && (par->text_node->par == par))
|
2011-04-14 05:13:20 -07:00
|
|
|
par->text_node->par = NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
free(par);
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Clear all the paragraphs from the inlist pars.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - Not NULL.
|
|
|
|
* @param pars the paragraphs to clean - Not NULL.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_paragraphs_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
|
2011-01-30 02:41:42 -08:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(pars), par)
|
|
|
|
{
|
|
|
|
_paragraph_clear(obj, par);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Free the paragraphs from the inlist pars, the difference between this and
|
|
|
|
* _paragraphs_clear is that the latter keeps the logical items and the par
|
|
|
|
* items, while the former frees them as well.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - Not NULL.
|
|
|
|
* @param pars the paragraphs to clean - Not NULL.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_paragraphs_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-15 01:17:21 -07:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
while (pars)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
|
|
|
|
|
|
|
par = (Evas_Object_Textblock_Paragraph *) pars;
|
|
|
|
pars = (Evas_Object_Textblock_Paragraph *)eina_inlist_remove(EINA_INLIST_GET(pars), EINA_INLIST_GET(par));
|
|
|
|
_paragraph_free(obj, par);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Push fmt to the format stack, if fmt is NULL, will fush a default item.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to push.
|
|
|
|
* @see _layout_format_pop()
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static Evas_Object_Textblock_Format *
|
|
|
|
_layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
|
|
|
{
|
|
|
|
if (fmt)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt = _format_dup(c->obj, fmt);
|
|
|
|
c->format_stack = eina_list_prepend(c->format_stack, fmt);
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else
|
2005-08-16 02:25:48 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt = calloc(1, sizeof(Evas_Object_Textblock_Format));
|
|
|
|
c->format_stack = eina_list_prepend(c->format_stack, fmt);
|
|
|
|
fmt->ref = 1;
|
|
|
|
fmt->halign = 0.0;
|
2010-08-11 00:23:48 -07:00
|
|
|
fmt->halign_auto = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt->valign = -1.0;
|
|
|
|
fmt->style = EVAS_TEXT_STYLE_PLAIN;
|
|
|
|
fmt->tabstops = 32;
|
2009-09-03 20:53:18 -07:00
|
|
|
fmt->linesize = 0;
|
|
|
|
fmt->linerelsize = 0.0;
|
2010-04-12 01:23:53 -07:00
|
|
|
fmt->linegap = 0;
|
|
|
|
fmt->linerelgap = 0.0;
|
2011-04-28 04:08:20 -07:00
|
|
|
fmt->password = 1;
|
2005-08-16 02:25:48 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
return fmt;
|
2005-08-03 06:07:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Pop fmt to the format stack, if there's something in the stack free fmt
|
|
|
|
* and set it to point to the next item instead, else return fmt.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to free.
|
|
|
|
* @return the next format in the stack, or format if there's none.
|
2011-03-20 06:56:08 -07:00
|
|
|
* @see _layout_format_push()
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static Evas_Object_Textblock_Format *
|
|
|
|
_layout_format_pop(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
2005-08-03 06:07:00 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
if ((c->format_stack) && (c->format_stack->next))
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_unref_free(c->obj, fmt);
|
|
|
|
c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack);
|
|
|
|
fmt = c->format_stack->data;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
return fmt;
|
2005-02-16 05:57:41 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Parse item and fill fmt with the item.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to fill - not null.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2010-08-09 09:24:17 -07:00
|
|
|
_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2006-11-28 08:14:11 -08:00
|
|
|
const char *key = NULL, *val = NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
char *tmp;
|
|
|
|
tmp = alloca(strlen(item) + 1);
|
|
|
|
strcpy(tmp, item);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_param_parse(tmp, &key, &val);
|
2005-08-20 01:01:59 -07:00
|
|
|
if ((key) && (val)) _format_command(c->obj, fmt, key, val);
|
2008-10-15 07:38:34 -07:00
|
|
|
if (key) eina_stringshare_del(key);
|
|
|
|
if (val) eina_stringshare_del(val);
|
2005-08-20 01:01:59 -07:00
|
|
|
c->align = fmt->halign;
|
2010-08-11 00:23:48 -07:00
|
|
|
c->align_auto = fmt->halign_auto;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->marginl = fmt->margin.l;
|
|
|
|
c->marginr = fmt->margin.r;
|
2005-08-08 02:01:07 -07:00
|
|
|
}
|
|
|
|
|
2010-04-25 04:35:41 -07:00
|
|
|
#define VSIZE_FULL 0
|
|
|
|
#define VSIZE_ASCENT 1
|
|
|
|
|
|
|
|
#define SIZE 0
|
|
|
|
#define SIZE_ABS 1
|
|
|
|
#define SIZE_REL 2
|
|
|
|
|
2010-08-11 00:23:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Get the current line's alignment from the context.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
*/
|
|
|
|
static inline double
|
|
|
|
_layout_line_align_get(Ctxt *c)
|
|
|
|
{
|
|
|
|
#ifdef BIDI_SUPPORT
|
2011-01-30 02:31:08 -08:00
|
|
|
if (c->align_auto && c->ln)
|
2010-08-11 00:23:48 -07:00
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
if (c->ln->items && c->ln->items->text_node &&
|
2011-01-30 02:31:08 -08:00
|
|
|
EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(
|
2011-04-14 05:13:20 -07:00
|
|
|
c->ln->par->bidi_props))
|
2010-08-11 00:23:48 -07:00
|
|
|
{
|
|
|
|
/* Align right*/
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Align left */
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return c->align;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:31:08 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-01-30 02:45:45 -08:00
|
|
|
* Reorder the items in visual order
|
2011-01-30 02:31:08 -08:00
|
|
|
*
|
|
|
|
* @param line the line to reorder
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-30 02:40:14 -08:00
|
|
|
_layout_line_order(Ctxt *c __UNUSED__, Evas_Object_Textblock_Line *line)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
|
|
|
/*FIXME: do it a bit more efficient - not very efficient ATM. */
|
2011-01-30 02:40:14 -08:00
|
|
|
#ifdef BIDI_SUPPORT
|
2011-01-30 02:31:08 -08:00
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
EvasBiDiStrIndex *v_to_l = NULL;
|
|
|
|
size_t start, end;
|
|
|
|
size_t len;
|
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
if (line->items && line->items->text_node &&
|
2011-04-14 05:13:20 -07:00
|
|
|
line->par->bidi_props)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
Evas_BiDi_Paragraph_Props *props;
|
2011-04-14 05:13:20 -07:00
|
|
|
props = line->par->bidi_props;
|
2011-01-30 02:31:16 -08:00
|
|
|
start = end = line->items->text_pos;
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
/* Find the first and last positions in the line */
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
EINA_INLIST_FOREACH(line->items, it)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
if (it->text_pos < start)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
start = it->text_pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int tlen;
|
|
|
|
tlen = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
|
2011-02-14 05:09:41 -08:00
|
|
|
_ITEM_TEXT(it)->text_props.text_len : 1;
|
2011-01-30 02:40:14 -08:00
|
|
|
if (it->text_pos + tlen > end)
|
|
|
|
{
|
|
|
|
end = it->text_pos + tlen;
|
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
len = end - start;
|
|
|
|
evas_bidi_props_reorder_line(NULL, start, len, props, &v_to_l);
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
/* Update visual pos */
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
Evas_Object_Textblock_Item *i;
|
|
|
|
i = line->items;
|
|
|
|
while (i)
|
|
|
|
{
|
|
|
|
i->visual_pos = evas_bidi_position_logical_to_visual(
|
|
|
|
v_to_l, len, i->text_pos - start);
|
|
|
|
i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(i)->next;
|
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
/*FIXME: not very efficient, sort the items arrays. Anyhow, should only
|
|
|
|
* reorder if it's a bidi paragraph */
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
Evas_Object_Textblock_Item *i, *j, *min;
|
|
|
|
i = line->items;
|
|
|
|
while (i)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
min = i;
|
|
|
|
EINA_INLIST_FOREACH(i, j)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
if (j->visual_pos < min->visual_pos)
|
|
|
|
{
|
|
|
|
min = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (min != i)
|
|
|
|
{
|
|
|
|
line->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min));
|
|
|
|
line->items = (Evas_Object_Textblock_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(min)->next;
|
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v_to_l) free(v_to_l);
|
2011-03-18 20:56:35 -07:00
|
|
|
#else
|
|
|
|
line = NULL;
|
2011-01-30 02:31:08 -08:00
|
|
|
#endif
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-01-30 02:41:18 -08:00
|
|
|
* Order the items in the line, update it's properties and update it's
|
|
|
|
* corresponding paragraph.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to use.
|
2011-01-30 02:39:52 -08:00
|
|
|
* @param add_line true if we should create a line, false otherwise.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-08 02:01:07 -07:00
|
|
|
static void
|
2011-01-30 02:41:18 -08:00
|
|
|
_layout_line_finalize(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2011-01-30 02:45:11 -08:00
|
|
|
Evas_Object_Textblock_Item *it;
|
2011-01-30 02:31:16 -08:00
|
|
|
Eina_Bool no_text = EINA_TRUE;
|
2011-02-15 08:50:07 -08:00
|
|
|
Evas_Coord x = 0;
|
2008-10-17 04:23:18 -07:00
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
_layout_line_order(c, c->ln);
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2010-03-04 08:22:28 -08:00
|
|
|
c->maxascent = c->maxdescent = 0;
|
2011-01-30 02:31:16 -08:00
|
|
|
EINA_INLIST_FOREACH(c->ln->items, it)
|
|
|
|
{
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
no_text = EINA_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (no_text)
|
2010-03-04 08:22:28 -08:00
|
|
|
_layout_format_ascent_descent_adjust(c, fmt);
|
2011-01-30 02:31:16 -08:00
|
|
|
|
2010-03-04 07:02:10 -08:00
|
|
|
EINA_INLIST_FOREACH(c->ln->items, it)
|
2010-03-04 08:22:28 -08:00
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->font.font)
|
|
|
|
ti->baseline = c->ENFN->font_max_ascent_get(c->ENDT, ti->parent.format->font.font);
|
|
|
|
_layout_format_ascent_descent_adjust(c, ti->parent.format);
|
2011-01-30 02:31:16 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
|
2011-02-16 01:43:57 -08:00
|
|
|
if (!fi->formatme) goto loop_advance;
|
2011-01-30 02:42:41 -08:00
|
|
|
fi->ascent = c->maxascent;
|
|
|
|
fi->descent = c->maxdescent;
|
2011-01-30 02:42:48 -08:00
|
|
|
/* Adjust sizes according to current line height/scale */
|
2011-01-30 02:42:41 -08:00
|
|
|
{
|
2011-01-30 02:42:48 -08:00
|
|
|
Evas_Coord w, h;
|
2011-01-30 02:42:41 -08:00
|
|
|
const char *p, *s;
|
2011-01-30 02:42:48 -08:00
|
|
|
|
2011-01-30 02:42:41 -08:00
|
|
|
s = eina_strbuf_string_get(fi->source_node->format);
|
2011-01-30 02:42:48 -08:00
|
|
|
w = fi->parent.w;
|
|
|
|
h = fi->parent.h;
|
|
|
|
switch (fi->size)
|
2011-01-30 02:42:41 -08:00
|
|
|
{
|
2011-01-30 02:42:48 -08:00
|
|
|
case SIZE:
|
2011-01-30 02:42:56 -08:00
|
|
|
if (!strncmp(s, "item", 4))
|
2011-01-30 02:42:48 -08:00
|
|
|
{
|
2011-01-30 02:42:56 -08:00
|
|
|
p = strstr(s, " size=");
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p += 6;
|
|
|
|
if (sscanf(p, "%ix%i", &w, &h) == 2)
|
|
|
|
{
|
|
|
|
w = w * c->obj->cur.scale;
|
|
|
|
h = h * c->obj->cur.scale;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:42:48 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIZE_REL:
|
|
|
|
p = strstr((char *) s, " relsize=");
|
|
|
|
p += 9;
|
|
|
|
if (sscanf(p, "%ix%i", &w, &h) == 2)
|
|
|
|
{
|
|
|
|
int sz = 1;
|
|
|
|
if (fi->vsize == VSIZE_FULL)
|
|
|
|
{
|
|
|
|
sz = c->maxdescent + c->maxascent;
|
|
|
|
}
|
|
|
|
else if (fi->vsize == VSIZE_ASCENT)
|
|
|
|
{
|
|
|
|
sz = c->maxascent;
|
|
|
|
}
|
|
|
|
w = (w * sz) / h;
|
|
|
|
h = sz;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIZE_ABS:
|
|
|
|
/* Nothing to do */
|
|
|
|
default:
|
|
|
|
break;
|
2011-01-30 02:42:41 -08:00
|
|
|
}
|
|
|
|
fi->parent.w = fi->parent.adv = w;
|
|
|
|
fi->parent.h = h;
|
|
|
|
}
|
2011-01-30 02:42:48 -08:00
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
switch (fi->size)
|
|
|
|
{
|
|
|
|
case SIZE:
|
|
|
|
case SIZE_ABS:
|
|
|
|
switch (fi->vsize)
|
|
|
|
{
|
|
|
|
case VSIZE_FULL:
|
|
|
|
if (fi->parent.h > (c->maxdescent + c->maxascent))
|
|
|
|
{
|
|
|
|
c->maxascent += fi->parent.h - (c->maxdescent + c->maxascent);
|
|
|
|
fi->y = -c->maxascent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fi->y = -(fi->parent.h - c->maxdescent);
|
|
|
|
break;
|
|
|
|
case VSIZE_ASCENT:
|
|
|
|
if (fi->parent.h > c->maxascent)
|
|
|
|
{
|
|
|
|
c->maxascent = fi->parent.h;
|
|
|
|
fi->y = -fi->parent.h;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fi->y = -fi->parent.h;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIZE_REL:
|
|
|
|
switch (fi->vsize)
|
|
|
|
{
|
|
|
|
case VSIZE_FULL:
|
|
|
|
case VSIZE_ASCENT:
|
|
|
|
fi->y = -fi->ascent;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-04 07:02:10 -08:00
|
|
|
|
2011-02-16 01:43:57 -08:00
|
|
|
loop_advance:
|
2011-02-15 08:50:07 -08:00
|
|
|
it->x = x;
|
|
|
|
x += it->adv;
|
|
|
|
|
2011-03-29 06:52:35 -07:00
|
|
|
if ((it->x + it->w) > c->ln->w) c->ln->w = it->x + it->w;
|
2010-03-04 08:22:28 -08:00
|
|
|
}
|
2010-04-25 04:35:41 -07:00
|
|
|
|
2011-01-30 02:40:09 -08:00
|
|
|
c->ln->y = (c->y - c->par->y) + c->o->style_pad.t;
|
2010-03-04 08:22:28 -08:00
|
|
|
c->ln->h = c->maxascent + c->maxdescent;
|
|
|
|
c->ln->baseline = c->maxascent;
|
2005-08-20 01:01:59 -07:00
|
|
|
if (c->have_underline2)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent;
|
2005-08-08 02:01:07 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else if (c->have_underline)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent;
|
2005-08-08 02:01:07 -07:00
|
|
|
}
|
2011-01-30 02:39:52 -08:00
|
|
|
c->ln->line_no = c->line_no - c->ln->par->line_no;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->line_no++;
|
2010-03-04 08:22:28 -08:00
|
|
|
c->y += c->maxascent + c->maxdescent;
|
|
|
|
if (c->w >= 0)
|
|
|
|
{
|
2011-01-30 02:40:21 -08:00
|
|
|
c->ln->x = c->marginl + c->o->style_pad.l +
|
2010-08-09 09:24:17 -07:00
|
|
|
((c->w - c->ln->w -
|
|
|
|
c->o->style_pad.l - c->o->style_pad.r -
|
2010-08-11 00:23:48 -07:00
|
|
|
c->marginl - c->marginr) * _layout_line_align_get(c));
|
2010-03-04 08:22:28 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:40:21 -08:00
|
|
|
c->ln->x = c->marginl + c->o->style_pad.l;
|
2010-03-04 08:22:28 -08:00
|
|
|
}
|
2011-05-02 00:27:48 -07:00
|
|
|
|
|
|
|
{
|
|
|
|
Evas_Coord new_wmax = c->par->x + c->ln->x + c->ln->w +
|
|
|
|
c->marginl + c->marginr - (c->o->style_pad.l + c->o->style_pad.r);
|
|
|
|
if (new_wmax > c->wmax)
|
|
|
|
c->wmax = new_wmax;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:21 -08:00
|
|
|
c->par->h = c->ln->y + c->ln->h;
|
2011-01-30 02:45:06 -08:00
|
|
|
if (c->ln->w + c->ln->x > c->par->w)
|
|
|
|
c->par->w = c->ln->x + c->ln->w;
|
2011-01-30 02:41:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create a new line and append it to the lines in the context.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to use.
|
|
|
|
* @param add_line true if we should create a line, false otherwise.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
|
|
|
{
|
|
|
|
_layout_line_finalize(c, fmt);
|
|
|
|
_layout_line_new(c, fmt);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-01-30 02:31:16 -08:00
|
|
|
* Create a new text layout item from the string and the format.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to use.
|
|
|
|
* @param str the string to use.
|
2011-02-14 02:49:09 -08:00
|
|
|
* @param len the length of the string.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2011-01-30 02:31:16 -08:00
|
|
|
static Evas_Object_Textblock_Text_Item *
|
2011-04-13 01:36:57 -07:00
|
|
|
_layout_text_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
ti = calloc(1, sizeof(Evas_Object_Textblock_Text_Item));
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format = fmt;
|
|
|
|
ti->parent.format->ref++;
|
2011-01-30 02:31:16 -08:00
|
|
|
ti->parent.type = EVAS_TEXTBLOCK_ITEM_TEXT;
|
|
|
|
return ti;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Return the cutoff of the text in the text item.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param fmt the format to use. - Not NULL.
|
|
|
|
* @param it the item to check - Not null.
|
2011-01-30 02:31:08 -08:00
|
|
|
* @return -1 if there is no cutoff (either because there is really none,
|
|
|
|
* or because of an error), cutoff index on success.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static int
|
2011-01-30 02:40:21 -08:00
|
|
|
_layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt,
|
|
|
|
const Evas_Object_Textblock_Text_Item *ti)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2005-09-14 02:01:26 -07:00
|
|
|
if (fmt->font.font)
|
2011-01-30 02:40:21 -08:00
|
|
|
{
|
|
|
|
Evas_Coord x;
|
|
|
|
x = c->w - c->o->style_pad.l - c->o->style_pad.r - c->marginl -
|
2011-03-29 06:52:35 -07:00
|
|
|
c->marginr - c->x - ti->x_adjustment;
|
2011-01-30 02:40:21 -08:00
|
|
|
if (x < 0)
|
|
|
|
x = 0;
|
2011-04-07 09:25:56 -07:00
|
|
|
return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font,
|
2011-02-14 05:09:41 -08:00
|
|
|
&ti->text_props, x, 0);
|
2011-01-30 02:40:21 -08:00
|
|
|
}
|
2005-09-14 02:01:26 -07:00
|
|
|
return -1;
|
2005-08-08 02:01:07 -07:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:30 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-05-05 04:06:06 -07:00
|
|
|
* Split before cut, and strip if str[cut - 1] is a whitespace.
|
2011-01-30 02:40:30 -08:00
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
2011-02-14 01:37:49 -08:00
|
|
|
* @param ti the item to cut - not null.
|
|
|
|
* @param lti the logical list item of the item.
|
2011-01-30 02:40:30 -08:00
|
|
|
* @param cut the cut index.
|
|
|
|
* @return the second (newly created) item.
|
|
|
|
*/
|
|
|
|
static Evas_Object_Textblock_Text_Item *
|
|
|
|
_layout_item_text_split_strip_white(Ctxt *c,
|
2011-04-13 06:28:08 -07:00
|
|
|
Evas_Object_Textblock_Text_Item *ti, Eina_List *lti, size_t cut)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-04-13 01:36:57 -07:00
|
|
|
const Eina_Unicode *ts;
|
2011-02-01 04:17:38 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *new_ti = NULL, *white_ti = NULL;
|
2011-04-13 06:28:08 -07:00
|
|
|
size_t cut2;
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-04-13 01:36:57 -07:00
|
|
|
ts = GET_ITEM_TEXT(ti);
|
2011-05-05 04:06:06 -07:00
|
|
|
|
|
|
|
cut2 = cut;
|
|
|
|
/* Also strip the previous white */
|
|
|
|
if ((cut > 1) && _is_white(ts[cut - 1]))
|
|
|
|
cut--;
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-04-13 06:29:24 -07:00
|
|
|
if (!IS_AT_END(ti, cut2) && (ti->text_props.text_len > 0))
|
2011-02-01 04:17:38 -08:00
|
|
|
{
|
2011-04-13 01:36:57 -07:00
|
|
|
new_ti = _layout_text_item_new(c, ti->parent.format);
|
2011-02-01 04:17:38 -08:00
|
|
|
new_ti->parent.text_node = ti->parent.text_node;
|
|
|
|
new_ti->parent.text_pos = ti->parent.text_pos + cut2;
|
|
|
|
new_ti->parent.merge = EINA_TRUE;
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_split(&ti->text_props,
|
|
|
|
&new_ti->text_props, cut2);
|
2011-02-14 01:37:49 -08:00
|
|
|
_layout_text_add_logical_item(c, new_ti, lti);
|
2011-02-01 04:17:38 -08:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-02-24 07:18:10 -08:00
|
|
|
if ((cut2 > cut) && (ti->text_props.text_len > 0))
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-04-13 01:36:57 -07:00
|
|
|
white_ti = _layout_text_item_new(c, ti->parent.format);
|
2011-01-30 02:40:30 -08:00
|
|
|
white_ti->parent.text_node = ti->parent.text_node;
|
|
|
|
white_ti->parent.text_pos = ti->parent.text_pos + cut;
|
|
|
|
white_ti->parent.merge = EINA_TRUE;
|
|
|
|
white_ti->parent.visually_deleted = EINA_TRUE;
|
|
|
|
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_split(&ti->text_props,
|
|
|
|
&white_ti->text_props, cut);
|
2011-02-14 01:37:49 -08:00
|
|
|
_layout_text_add_logical_item(c, white_ti, lti);
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
|
2011-02-01 04:17:38 -08:00
|
|
|
if (new_ti || white_ti)
|
|
|
|
{
|
|
|
|
_text_item_update_sizes(c, ti);
|
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
return new_ti;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:41:42 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Merge item2 into item1 and free item2.
|
|
|
|
*
|
|
|
|
* @param c the context to work on - Not NULL.
|
|
|
|
* @param item1 the item to copy to
|
|
|
|
* @param item2 the item to copy from
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_layout_item_merge_and_free(Ctxt *c,
|
|
|
|
Evas_Object_Textblock_Text_Item *item1,
|
|
|
|
Evas_Object_Textblock_Text_Item *item2)
|
|
|
|
{
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_merge(&item1->text_props,
|
|
|
|
&item2->text_props);
|
2011-02-14 02:09:27 -08:00
|
|
|
|
2011-04-20 07:20:54 -07:00
|
|
|
_text_item_update_sizes(c, item1);
|
2011-02-14 04:44:38 -08:00
|
|
|
|
2011-01-30 02:41:42 -08:00
|
|
|
item1->parent.merge = EINA_FALSE;
|
|
|
|
item1->parent.visually_deleted = EINA_FALSE;
|
|
|
|
|
|
|
|
_item_free(c->obj, NULL, _ITEM(item2));
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:31:08 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-01-30 02:45:45 -08:00
|
|
|
* Calculates an item's size.
|
2011-01-30 02:31:08 -08:00
|
|
|
*
|
|
|
|
* @param c the context
|
|
|
|
* @param it the item itself.
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-30 02:45:45 -08:00
|
|
|
_text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-04-20 07:20:54 -07:00
|
|
|
int tw, th, inset, advw;
|
2011-01-30 02:45:45 -08:00
|
|
|
const Evas_Object_Textblock_Format *fmt = ti->parent.format;
|
2011-04-11 05:05:59 -07:00
|
|
|
int shad_sz = 0, shad_dst = 0, out_sz = 0;
|
|
|
|
int dx = 0, minx = 0, maxx = 0, shx1, shx2;
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:38:39 -08:00
|
|
|
tw = th = 0;
|
|
|
|
if (fmt->font.font)
|
2011-04-07 09:25:56 -07:00
|
|
|
c->ENFN->font_string_size_get(c->ENDT, fmt->font.font,
|
2011-02-14 05:09:41 -08:00
|
|
|
&ti->text_props, &tw, &th);
|
2011-01-30 02:38:39 -08:00
|
|
|
inset = 0;
|
|
|
|
if (fmt->font.font)
|
|
|
|
inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font,
|
2011-02-14 05:09:41 -08:00
|
|
|
&ti->text_props);
|
2011-04-20 07:20:54 -07:00
|
|
|
advw = 0;
|
2011-01-30 02:38:39 -08:00
|
|
|
if (fmt->font.font)
|
2011-04-20 07:20:54 -07:00
|
|
|
advw = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font,
|
|
|
|
&ti->text_props);
|
|
|
|
|
2011-03-29 06:52:35 -07:00
|
|
|
|
|
|
|
/* These adjustments are calculated and thus heavily linked to those in
|
|
|
|
* textblock_render!!! Don't change one without the other. */
|
2011-04-13 02:29:45 -07:00
|
|
|
|
2011-04-11 05:05:59 -07:00
|
|
|
switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC)
|
|
|
|
{
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW:
|
|
|
|
shad_dst = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
|
|
|
|
case EVAS_TEXT_STYLE_FAR_SHADOW:
|
|
|
|
shad_dst = 2;
|
|
|
|
out_sz = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
|
|
|
|
shad_dst = 1;
|
|
|
|
shad_sz = 2;
|
|
|
|
out_sz = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
|
|
|
|
shad_dst = 2;
|
|
|
|
shad_sz = 2;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SOFT_SHADOW:
|
|
|
|
shad_dst = 1;
|
|
|
|
shad_sz = 2;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_GLOW:
|
|
|
|
case EVAS_TEXT_STYLE_SOFT_OUTLINE:
|
|
|
|
out_sz = 2;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_OUTLINE:
|
|
|
|
out_sz = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
|
|
|
|
{
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
|
|
|
|
dx = -1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
|
|
|
|
dx = 1;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
|
|
|
|
default:
|
|
|
|
dx = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
minx = -out_sz;
|
|
|
|
maxx = out_sz;
|
|
|
|
shx1 = dx * shad_dst;
|
|
|
|
shx1 -= shad_sz;
|
|
|
|
shx2 = dx * shad_dst;
|
|
|
|
shx2 += shad_sz;
|
|
|
|
if (shx1 < minx) minx = shx1;
|
|
|
|
if (shx2 > maxx) maxx = shx2;
|
|
|
|
inset += -minx;
|
|
|
|
ti->x_adjustment = maxx - minx;
|
|
|
|
|
2011-03-29 06:52:35 -07:00
|
|
|
ti->inset = inset;
|
|
|
|
ti->parent.w = tw + ti->x_adjustment;
|
|
|
|
ti->parent.h = th;
|
2011-04-20 07:20:54 -07:00
|
|
|
ti->parent.adv = advw;
|
2011-01-30 02:40:14 -08:00
|
|
|
ti->parent.x = 0;
|
2011-01-30 02:45:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Adds the item to the list, updates the item's properties (e.g, x,w,h)
|
|
|
|
*
|
|
|
|
* @param c the context
|
|
|
|
* @param it the item itself.
|
|
|
|
* @param rel item ti will be appened after, NULL = last.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti,
|
2011-02-14 01:37:49 -08:00
|
|
|
Eina_List *rel)
|
2011-01-30 02:45:45 -08:00
|
|
|
{
|
|
|
|
_text_item_update_sizes(c, ti);
|
|
|
|
|
2011-02-14 01:37:49 -08:00
|
|
|
c->par->logical_items = eina_list_append_relative_list(
|
2011-01-30 02:40:30 -08:00
|
|
|
c->par->logical_items, ti, rel);
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Appends the text from node n starting at start ending at off to the layout.
|
|
|
|
* It uses the fmt for the formatting.
|
|
|
|
*
|
|
|
|
* @param c the current context- NOT NULL.
|
|
|
|
* @param fmt the format to use.
|
|
|
|
* @param n the text node. - Not null.
|
|
|
|
* @param start the start position. - in range.
|
|
|
|
* @param off the offset - start + offset in range. if offset is -1, it'll add everything to the end of the string if offset = 0 it'll return with doing nothing.
|
2010-09-21 08:39:26 -07:00
|
|
|
* @param repch a replacement char to print instead of the original string, for example, * when working with passwords.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-08 02:01:07 -07:00
|
|
|
static void
|
2010-08-09 09:24:17 -07:00
|
|
|
_layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node_Text *n, int start, int off, const char *repch)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2011-01-30 02:40:14 -08:00
|
|
|
int new_line, empty_item;
|
2010-08-09 09:24:17 -07:00
|
|
|
Eina_Unicode *alloc_str = NULL;
|
2010-07-28 05:00:41 -07:00
|
|
|
const Eina_Unicode *str = EINA_UNICODE_EMPTY_STRING;
|
|
|
|
const Eina_Unicode *tbase;
|
2011-01-30 02:31:16 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2011-02-14 02:49:09 -08:00
|
|
|
size_t cur_len = 0;
|
2011-04-21 08:34:44 -07:00
|
|
|
Eina_Unicode urepch = 0;
|
2008-10-22 01:57:30 -07:00
|
|
|
|
2010-09-21 08:39:26 -07:00
|
|
|
/* prepare a working copy of the string, either filled by the repch or
|
|
|
|
* filled with the true values */
|
2010-03-12 02:49:39 -08:00
|
|
|
if (n)
|
2008-10-22 01:57:30 -07:00
|
|
|
{
|
2010-09-20 03:06:01 -07:00
|
|
|
int len;
|
|
|
|
int orig_off = off;
|
2010-09-21 08:39:26 -07:00
|
|
|
|
|
|
|
/* Figure out if we want to bail, work with an empty string,
|
|
|
|
* or continue with a slice of the passed string */
|
2010-09-20 03:06:01 -07:00
|
|
|
len = eina_ustrbuf_length_get(n->unicode);
|
|
|
|
if (off == 0) return;
|
|
|
|
else if (off < 0) off = len - start;
|
|
|
|
|
|
|
|
if (start < 0)
|
|
|
|
{
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
else if ((start == 0) && (off == 0) && (orig_off == -1))
|
|
|
|
{
|
|
|
|
/* Special case that means that we need to add an empty
|
|
|
|
* item */
|
|
|
|
str = EINA_UNICODE_EMPTY_STRING;
|
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
else if ((start >= len) || (start + off > len))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2010-09-21 08:39:26 -07:00
|
|
|
|
|
|
|
/* If we work with a replacement char, create a string which is the same
|
|
|
|
* but with replacement chars instead of regular chars. */
|
2011-04-28 04:08:20 -07:00
|
|
|
if ((fmt->password) && (repch) && (eina_ustrbuf_length_get(n->unicode)))
|
2010-03-12 02:49:39 -08:00
|
|
|
{
|
2010-09-20 03:06:01 -07:00
|
|
|
int i, ind;
|
2010-07-28 05:00:41 -07:00
|
|
|
Eina_Unicode *ptr;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2011-04-21 07:04:46 -07:00
|
|
|
tbase = str = ptr = alloca((off + 1) * sizeof(Eina_Unicode));
|
2010-07-28 05:00:41 -07:00
|
|
|
ind = 0;
|
2011-02-16 08:00:17 -08:00
|
|
|
urepch = eina_unicode_utf8_get_next(repch, &ind);
|
2011-04-21 07:04:46 -07:00
|
|
|
for (i = 0 ; i < off; ptr++, i++)
|
2010-08-09 09:24:17 -07:00
|
|
|
*ptr = urepch;
|
2010-03-12 02:49:39 -08:00
|
|
|
*ptr = 0;
|
|
|
|
}
|
2010-09-21 08:39:26 -07:00
|
|
|
/* Use the string, just cut the relevant parts */
|
2010-03-12 02:49:39 -08:00
|
|
|
else
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
str = eina_ustrbuf_string_get(n->unicode);
|
2011-02-08 05:44:41 -08:00
|
|
|
alloc_str = eina_unicode_strndup(str + start, off);
|
2010-08-12 07:20:19 -07:00
|
|
|
str = alloc_str;
|
2010-03-12 02:49:39 -08:00
|
|
|
}
|
2011-02-14 02:49:09 -08:00
|
|
|
|
|
|
|
cur_len = off;
|
2008-10-22 01:57:30 -07:00
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2010-08-12 07:20:19 -07:00
|
|
|
skip:
|
|
|
|
tbase = str;
|
2005-08-20 01:01:59 -07:00
|
|
|
new_line = 0;
|
|
|
|
empty_item = 0;
|
2010-07-28 05:00:41 -07:00
|
|
|
|
2011-01-30 02:31:51 -08:00
|
|
|
|
2011-01-30 02:42:35 -08:00
|
|
|
while (str)
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2011-01-30 02:39:03 -08:00
|
|
|
int tmp_len;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2011-04-13 01:36:57 -07:00
|
|
|
ti = _layout_text_item_new(c, fmt);
|
2011-01-30 02:31:16 -08:00
|
|
|
ti->parent.text_node = n;
|
|
|
|
ti->parent.text_pos = start + str - tbase;
|
2011-01-30 02:39:03 -08:00
|
|
|
tmp_len = off - (str - tbase);
|
2011-01-30 02:31:16 -08:00
|
|
|
if (ti->parent.text_node)
|
2010-08-12 07:59:42 -07:00
|
|
|
{
|
2011-01-30 02:38:39 -08:00
|
|
|
int tmp_cut;
|
2011-04-14 05:34:29 -07:00
|
|
|
tmp_cut = evas_common_language_script_end_of_run_get(str,
|
|
|
|
c->par->bidi_props, ti->parent.text_pos, tmp_len);
|
2011-01-30 02:38:39 -08:00
|
|
|
if (tmp_cut > 0)
|
|
|
|
{
|
|
|
|
tmp_len = tmp_cut;
|
|
|
|
}
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_bidi_set(&ti->text_props,
|
2011-04-14 05:13:20 -07:00
|
|
|
c->par->bidi_props, ti->parent.text_pos);
|
2011-04-14 05:34:29 -07:00
|
|
|
evas_common_text_props_script_set(&ti->text_props, str, tmp_len);
|
2011-03-22 03:18:46 -07:00
|
|
|
if (ti->parent.format->font.font)
|
|
|
|
{
|
|
|
|
c->ENFN->font_text_props_info_create(c->ENDT,
|
2011-04-14 05:34:29 -07:00
|
|
|
ti->parent.format->font.font, str, &ti->text_props,
|
|
|
|
c->par->bidi_props, ti->parent.text_pos, tmp_len);
|
2011-03-22 03:18:46 -07:00
|
|
|
}
|
2010-08-12 07:59:42 -07:00
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
str += tmp_len;
|
2011-02-14 02:49:09 -08:00
|
|
|
cur_len -= tmp_len;
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
_layout_text_add_logical_item(c, ti, NULL);
|
2011-01-30 02:42:35 -08:00
|
|
|
|
|
|
|
/* Break if we reached the end. */
|
|
|
|
if (!*str)
|
|
|
|
break;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (alloc_str) free(alloc_str);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2005-08-11 06:50:37 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Add a format item from the format node n and the item item.
|
|
|
|
*
|
|
|
|
* @param c the current context- NOT NULL.
|
|
|
|
* @param n the source format node - not null.
|
2011-01-30 02:41:49 -08:00
|
|
|
* @param item the format text.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @return the new format item.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
static Evas_Object_Textblock_Format_Item *
|
2011-01-30 02:40:47 -08:00
|
|
|
_layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const char *item, Evas_Object_Textblock_Format *fmt)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
fi = calloc(1, sizeof(Evas_Object_Textblock_Format_Item));
|
2008-10-15 07:38:34 -07:00
|
|
|
fi->item = eina_stringshare_add(item);
|
2005-08-20 22:13:49 -07:00
|
|
|
fi->source_node = n;
|
2011-01-30 02:31:16 -08:00
|
|
|
fi->parent.type = EVAS_TEXTBLOCK_ITEM_FORMAT;
|
2011-01-30 02:40:47 -08:00
|
|
|
fi->parent.format = fmt;
|
|
|
|
fi->parent.format->ref++;
|
2011-01-30 02:40:14 -08:00
|
|
|
c->par->logical_items = eina_list_append(c->par->logical_items, fi);
|
2011-01-30 02:31:08 -08:00
|
|
|
if (n)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
fi->parent.text_node = n->text_node;
|
2011-01-30 02:31:08 -08:00
|
|
|
/* FIXME: make it more efficient */
|
2011-01-30 02:31:16 -08:00
|
|
|
fi->parent.text_pos = _evas_textblock_node_format_pos_get(n);
|
2011-02-14 05:09:41 -08:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
fi->bidi_dir = (evas_bidi_is_rtl_char(
|
2011-04-14 05:13:20 -07:00
|
|
|
c->par->bidi_props,
|
2011-02-14 05:09:41 -08:00
|
|
|
0,
|
|
|
|
fi->parent.text_pos)) ?
|
|
|
|
EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
|
|
|
|
#else
|
|
|
|
fi->bidi_dir = EVAS_BIDI_DIRECTION_LTR;
|
|
|
|
#endif
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
return fi;
|
|
|
|
}
|
|
|
|
|
2011-05-05 06:38:04 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns true if the item is a tab
|
|
|
|
* @def _IS_TAB(item)
|
|
|
|
*/
|
|
|
|
#define _IS_TAB(item) \
|
|
|
|
(!strcmp(item, "\t") || !strcmp(item, "\\t"))
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns true if the item is a line spearator, false otherwise
|
|
|
|
* @def _IS_LINE_SEPARATOR(item)
|
|
|
|
*/
|
2010-07-28 05:00:41 -07:00
|
|
|
#define _IS_LINE_SEPARATOR(item) \
|
2010-08-09 09:24:17 -07:00
|
|
|
(!strcmp(item, "\n") || !strcmp(item, "\\n"))
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns true if the item is a paragraph separator, false otherwise
|
|
|
|
* @def _IS_PARAGRAPH_SEPARATOR(item)
|
|
|
|
*/
|
2011-02-14 06:17:12 -08:00
|
|
|
#define _IS_PARAGRAPH_SEPARATOR(o, item) \
|
|
|
|
(!strcmp(item, "ps") || \
|
|
|
|
(o->newline_is_ps && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
2010-09-07 20:51:24 -07:00
|
|
|
* Handles a format by processing a format node. It returns the relevant format
|
|
|
|
* through _fmt and updates the padding through style_pad_*. If needed,
|
2010-08-10 07:36:48 -07:00
|
|
|
* it creates a format item.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - NOT NULL.
|
|
|
|
* @param c the current context- NOT NULL.
|
|
|
|
* @param _fmt the format that holds the result.
|
|
|
|
* @param n the source format node - not null.
|
|
|
|
* @param style_pad_l the pad to update.
|
|
|
|
* @param style_pad_r the pad to update.
|
|
|
|
* @param style_pad_t the pad to update.
|
|
|
|
* @param style_pad_b the pad to update.
|
2011-04-07 07:25:48 -07:00
|
|
|
* @param create_item Create a new format item if true, only process otherwise.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
2011-01-30 02:42:48 -08:00
|
|
|
_layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c,
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n,
|
2011-04-07 07:25:48 -07:00
|
|
|
int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b,
|
|
|
|
Eina_Bool create_item)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format *fmt = *_fmt;
|
2010-08-10 07:36:48 -07:00
|
|
|
/* FIXME: comment the algo */
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
const char *s;
|
|
|
|
const char *item;
|
|
|
|
int handled = 0;
|
|
|
|
|
|
|
|
s = eina_strbuf_string_get(n->format);
|
|
|
|
if (!strncmp(s, "+ item ", 7))
|
|
|
|
{
|
|
|
|
// one of:
|
|
|
|
// item size=20x10 href=name
|
|
|
|
// item relsize=20x10 href=name
|
|
|
|
// item abssize=20x10 href=name
|
|
|
|
//
|
|
|
|
// optional arguments:
|
|
|
|
// vsize=full
|
|
|
|
// vsize=ascent
|
|
|
|
//
|
|
|
|
// size == item size (modifies line size) - can be multiplied by
|
|
|
|
// scale factor
|
|
|
|
// relsize == relative size (height is current font height, width
|
|
|
|
// modified accordingly keeping aspect)
|
|
|
|
// abssize == absolute size (modifies line size) - never mulitplied by
|
|
|
|
// scale factor
|
|
|
|
// href == name of item - to be found and matched later and used for
|
|
|
|
// positioning
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
2011-01-30 02:42:41 -08:00
|
|
|
int w = 1, h = 1;
|
2010-08-09 09:24:17 -07:00
|
|
|
int vsize = 0, size = 0;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
// don't care
|
|
|
|
//href = strstr(s, " href=");
|
|
|
|
p = strstr(s, " vsize=");
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p += 7;
|
|
|
|
if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL;
|
|
|
|
else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT;
|
|
|
|
}
|
|
|
|
p = strstr(s, " size=");
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p += 6;
|
|
|
|
if (sscanf(p, "%ix%i", &w, &h) == 2)
|
|
|
|
{
|
2011-01-30 02:42:48 -08:00
|
|
|
/* this is handled somewhere else because it depends
|
|
|
|
* on the current scaling factor of the object which
|
|
|
|
* may change and break because the results of this
|
|
|
|
* function are cached */
|
2010-08-09 09:24:17 -07:00
|
|
|
size = SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = strstr(s, " absize=");
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p += 8;
|
|
|
|
if (sscanf(p, "%ix%i", &w, &h) == 2)
|
|
|
|
{
|
|
|
|
size = SIZE_ABS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = strstr(s, " relsize=");
|
|
|
|
if (p)
|
|
|
|
{
|
2011-01-30 02:42:48 -08:00
|
|
|
/* this is handled somewhere else because it depends
|
|
|
|
* on the line it resides in, which is not defined
|
|
|
|
* at this point and will change anyway, which will
|
|
|
|
* break because the results of this function are
|
|
|
|
* cached */
|
2011-01-30 02:42:41 -08:00
|
|
|
size = SIZE_REL;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-07 07:25:48 -07:00
|
|
|
if (create_item)
|
|
|
|
{
|
|
|
|
fi = _layout_format_item_add(c, n, NULL, fmt);
|
|
|
|
fi->vsize = vsize;
|
|
|
|
fi->size = size;
|
|
|
|
fi->formatme = 1;
|
|
|
|
/* For formats items it's usually
|
|
|
|
the same, we don't handle the
|
|
|
|
special cases yet. */
|
|
|
|
fi->parent.w = fi->parent.adv = w;
|
|
|
|
fi->parent.h = h;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
handled = 1;
|
|
|
|
}
|
2011-04-07 07:25:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!handled)
|
|
|
|
{
|
|
|
|
if (s[0] == '+')
|
|
|
|
{
|
|
|
|
fmt = _layout_format_push(c, fmt);
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
else if (s[0] == '-')
|
|
|
|
{
|
|
|
|
fmt = _layout_format_pop(c, fmt);
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
while ((item = _format_parse(&s)))
|
|
|
|
{
|
|
|
|
char *tmp = alloca(s - item + 1);
|
|
|
|
strncpy(tmp, item, s - item);
|
|
|
|
tmp[s - item] = '\0';
|
|
|
|
if (_format_is_param(item))
|
|
|
|
{
|
|
|
|
_layout_format_value_handle(c, fmt, item);
|
|
|
|
}
|
2011-04-07 07:25:48 -07:00
|
|
|
else if (create_item)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2011-02-14 06:17:12 -08:00
|
|
|
if ((_IS_PARAGRAPH_SEPARATOR(c->o, item)) ||
|
2011-01-30 02:39:52 -08:00
|
|
|
(_IS_LINE_SEPARATOR(item)))
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
|
2011-04-07 08:25:19 -07:00
|
|
|
fi = _layout_format_item_add(c, n, item, fmt);
|
2011-04-07 06:13:41 -07:00
|
|
|
|
2011-01-30 02:33:19 -08:00
|
|
|
fi->parent.w = fi->parent.adv = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t")))
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
|
2011-01-30 02:40:47 -08:00
|
|
|
fi = _layout_format_item_add(c, n, item, fmt);
|
2011-02-15 08:50:14 -08:00
|
|
|
fi->parent.w = fi->parent.adv = fmt->tabstops;
|
2010-09-15 05:45:06 -07:00
|
|
|
fi->formatme = 1;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
evas_text_style_pad_get(fmt->style, style_pad_l, style_pad_r, style_pad_t, style_pad_b);
|
|
|
|
|
|
|
|
if (fmt->underline2)
|
|
|
|
c->have_underline2 = 1;
|
|
|
|
else if (fmt->underline)
|
|
|
|
c->have_underline = 1;
|
|
|
|
*_fmt = fmt;
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
static void
|
|
|
|
_layout_update_par(Ctxt *c)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *last_par;
|
|
|
|
last_par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->prev;
|
|
|
|
if (last_par)
|
|
|
|
{
|
|
|
|
c->par->y = last_par->y + last_par->h;
|
|
|
|
}
|
2011-03-30 05:19:05 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
c->par->y = 0;
|
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
|
|
|
/* -1 means no wrap */
|
|
|
|
static int
|
|
|
|
_layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
|
2011-05-05 06:38:09 -07:00
|
|
|
const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
|
|
|
|
const char *breaks)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
|
|
|
int wrap;
|
2011-04-13 01:36:57 -07:00
|
|
|
const Eina_Unicode *str = GET_ITEM_TEXT(ti);
|
2011-05-05 04:06:06 -07:00
|
|
|
/* Currently not being used, because it doesn't contain relevant
|
|
|
|
* information */
|
|
|
|
(void) breaks;
|
2011-05-05 06:38:09 -07:00
|
|
|
/* Currently not being used, because we don't enforce the ligature breaking
|
|
|
|
here just yet. */
|
|
|
|
(void) line_start;
|
2011-01-30 02:40:30 -08:00
|
|
|
|
|
|
|
wrap = _layout_text_cutoff_get(c, fmt, ti);
|
|
|
|
if (wrap == 0)
|
2011-04-13 01:36:57 -07:00
|
|
|
GET_NEXT(str, ti, wrap);
|
|
|
|
if ((wrap < 0) || IS_AT_END(ti, (size_t) wrap))
|
2011-05-05 06:38:09 -07:00
|
|
|
return -1;
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-05-05 06:38:09 -07:00
|
|
|
return wrap + ti->parent.text_pos;
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -1 means no wrap */
|
2011-05-05 04:06:06 -07:00
|
|
|
#ifdef HAVE_LINEBREAK
|
|
|
|
|
|
|
|
/* Allow break means: if we can break after the current char */
|
|
|
|
#define ALLOW_BREAK(i) \
|
2011-05-05 06:38:09 -07:00
|
|
|
(breaks[i] == LINEBREAK_ALLOWBREAK)
|
2011-05-05 04:06:06 -07:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define ALLOW_BREAK(i) \
|
2011-05-05 06:38:09 -07:00
|
|
|
(_is_white(str[i]))
|
2011-05-05 04:06:06 -07:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2011-05-05 06:38:09 -07:00
|
|
|
#define MOVE_PREV_UNTIL(line_start, ind) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
if ((line_start) < (ind)) \
|
|
|
|
(ind)--; \
|
|
|
|
} \
|
|
|
|
while (0)
|
|
|
|
|
|
|
|
#define MOVE_NEXT_UNTIL(len, ind) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
if ((ind) < (len)) \
|
|
|
|
(ind)++; \
|
|
|
|
} \
|
|
|
|
while (0)
|
2011-01-30 02:40:30 -08:00
|
|
|
static int
|
2011-01-30 02:43:21 -08:00
|
|
|
_layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt,
|
2011-05-05 04:06:06 -07:00
|
|
|
const Evas_Object_Textblock_Text_Item *ti, Eina_Bool mixed_wrap,
|
2011-05-05 06:38:09 -07:00
|
|
|
int line_start, const char *breaks)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-05-05 04:06:06 -07:00
|
|
|
int wrap = -1;
|
2011-01-30 02:43:21 -08:00
|
|
|
int orig_wrap;
|
2011-05-05 06:38:09 -07:00
|
|
|
const Eina_Unicode *str = eina_ustrbuf_string_get(
|
|
|
|
ti->parent.text_node->unicode);
|
|
|
|
int item_start = ti->parent.text_pos;
|
|
|
|
int len = eina_ustrbuf_length_get(ti->parent.text_node->unicode);
|
2011-05-05 04:06:06 -07:00
|
|
|
#ifndef HAVE_LINEBREAK
|
|
|
|
/* Not used without liblinebreak ATM. */
|
|
|
|
(void) breaks;
|
|
|
|
#endif
|
2011-01-30 02:40:30 -08:00
|
|
|
|
|
|
|
wrap = _layout_text_cutoff_get(c, fmt, ti);
|
2011-05-05 04:06:06 -07:00
|
|
|
/* Avoiding too small textblocks to even contain one char.
|
|
|
|
* FIXME: This can cause breaking inside ligatures. */
|
|
|
|
|
2011-05-05 06:38:09 -07:00
|
|
|
if (wrap < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
orig_wrap = wrap = wrap + item_start;
|
|
|
|
|
|
|
|
if (wrap > line_start)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-05-05 04:06:06 -07:00
|
|
|
/* The wrapping point found is the first char of the next string
|
|
|
|
the rest works on the last char of the previous string.
|
|
|
|
If it's a whitespace, then it's ok, and no need to go back
|
|
|
|
because we'll remove it anyway. */
|
|
|
|
if (!_is_white(str[wrap]))
|
2011-05-05 06:38:09 -07:00
|
|
|
MOVE_PREV_UNTIL(line_start, wrap);
|
2011-05-05 04:06:06 -07:00
|
|
|
/* If there's a breakable point inside the text, scan backwards until
|
|
|
|
* we find it */
|
2011-05-05 06:38:09 -07:00
|
|
|
while (wrap >= line_start)
|
2011-05-05 04:06:06 -07:00
|
|
|
{
|
|
|
|
if (ALLOW_BREAK(wrap))
|
|
|
|
break;
|
|
|
|
wrap--;
|
|
|
|
}
|
|
|
|
|
2011-05-05 06:38:09 -07:00
|
|
|
if (wrap >= line_start)
|
2011-05-05 04:06:06 -07:00
|
|
|
{
|
|
|
|
/* We found a suitable wrapping point, break here. */
|
2011-05-05 06:38:09 -07:00
|
|
|
MOVE_NEXT_UNTIL(len, wrap);
|
2011-05-05 04:06:06 -07:00
|
|
|
return wrap;
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-05-05 06:38:09 -07:00
|
|
|
/* If this is the start of the line, we should just try creating a
|
|
|
|
new line for it */
|
|
|
|
if (line_start < item_start)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-05 04:06:06 -07:00
|
|
|
|
|
|
|
if (mixed_wrap)
|
|
|
|
{
|
2011-05-05 06:38:09 -07:00
|
|
|
return ((orig_wrap >= line_start) && (orig_wrap < len)) ?
|
|
|
|
((int) orig_wrap) : -1;
|
2011-05-05 04:06:06 -07:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
else
|
|
|
|
{
|
2011-05-05 04:06:06 -07:00
|
|
|
/* Scan forward to find the next wrapping point */
|
2011-05-05 06:38:09 -07:00
|
|
|
wrap = item_start;
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-05 06:38:09 -07:00
|
|
|
|
|
|
|
/* If we need to find the position after the cutting point */
|
|
|
|
if (wrap == line_start)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-05-05 06:38:09 -07:00
|
|
|
while (wrap < len)
|
|
|
|
{
|
|
|
|
if (ALLOW_BREAK(wrap))
|
|
|
|
break;
|
|
|
|
wrap++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (wrap < len)
|
|
|
|
{
|
|
|
|
MOVE_NEXT_UNTIL(len, wrap);
|
|
|
|
return wrap;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2011-05-05 04:06:06 -07:00
|
|
|
return wrap;
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
2011-05-05 04:06:06 -07:00
|
|
|
|
2011-01-30 02:40:30 -08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:43:21 -08:00
|
|
|
/* -1 means no wrap */
|
|
|
|
static int
|
|
|
|
_layout_get_wordwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
|
2011-05-05 06:38:09 -07:00
|
|
|
const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
|
|
|
|
const char *breaks)
|
2011-01-30 02:43:21 -08:00
|
|
|
{
|
2011-05-05 06:38:09 -07:00
|
|
|
return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_FALSE, line_start,
|
|
|
|
breaks);
|
2011-01-30 02:43:21 -08:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:44:03 -08:00
|
|
|
/* -1 means no wrap */
|
|
|
|
static int
|
2011-01-30 02:43:21 -08:00
|
|
|
_layout_get_mixedwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
|
2011-05-05 06:38:09 -07:00
|
|
|
const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
|
|
|
|
const char *breaks)
|
2011-01-30 02:43:21 -08:00
|
|
|
{
|
2011-05-05 06:38:09 -07:00
|
|
|
return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_TRUE, line_start,
|
|
|
|
breaks);
|
2011-01-30 02:43:21 -08:00
|
|
|
}
|
|
|
|
|
2011-04-14 04:37:06 -07:00
|
|
|
/* Should be moved inside _layout_ellipsis_item_new once we fix the hack in
|
|
|
|
* textblock render */
|
|
|
|
static const Eina_Unicode _ellip_str[2] = { 0x2026, '\0' };
|
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
static Evas_Object_Textblock_Text_Item *
|
|
|
|
_layout_ellipsis_item_new(Ctxt *c, const Evas_Object_Textblock_Item *cur_it)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ellip_ti;
|
2011-02-14 02:49:05 -08:00
|
|
|
size_t len = 1; /* The length of _ellip_str */
|
2011-01-30 02:45:45 -08:00
|
|
|
ellip_ti = _layout_text_item_new(c,
|
2011-04-13 01:36:57 -07:00
|
|
|
eina_list_data_get(eina_list_last(c->format_stack)));
|
2011-01-30 02:45:45 -08:00
|
|
|
ellip_ti->parent.text_node = cur_it->text_node;
|
|
|
|
ellip_ti->parent.text_pos = cur_it->text_pos;
|
|
|
|
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_bidi_set(&ellip_ti->text_props,
|
2011-04-14 05:13:20 -07:00
|
|
|
c->par->bidi_props, ellip_ti->parent.text_pos);
|
2011-02-14 05:09:41 -08:00
|
|
|
evas_common_text_props_script_set (&ellip_ti->text_props,
|
2011-04-13 01:36:57 -07:00
|
|
|
_ellip_str, len);
|
2011-02-01 04:17:52 -08:00
|
|
|
c->ENFN->font_text_props_info_create(c->ENDT,
|
|
|
|
ellip_ti->parent.format->font.font,
|
2011-04-13 01:36:57 -07:00
|
|
|
_ellip_str, &ellip_ti->text_props,
|
2011-04-14 05:13:20 -07:00
|
|
|
c->par->bidi_props,
|
2011-02-14 02:49:05 -08:00
|
|
|
ellip_ti->parent.text_pos, len);
|
2011-01-30 02:45:45 -08:00
|
|
|
_text_item_update_sizes(c, ellip_ti);
|
|
|
|
|
2011-04-14 04:37:09 -07:00
|
|
|
if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
ellip_ti->parent.text_pos += _ITEM_TEXT(cur_it)->text_props.text_len
|
|
|
|
- 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ellip_ti->parent.text_pos++;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
return ellip_ti;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 0 means go ahead, 1 means break without an error, 2 means
|
|
|
|
* break with an error, should probably clean this a bit (enum/macro)
|
|
|
|
* FIXME ^ */
|
|
|
|
static int
|
2011-01-30 02:40:14 -08:00
|
|
|
_layout_visualize_par(Ctxt *c)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
Eina_List *i;
|
2011-05-05 04:06:06 -07:00
|
|
|
int ret = 0;
|
|
|
|
char *line_breaks = NULL;
|
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
if (!c->par->logical_items)
|
2011-01-30 02:45:45 -08:00
|
|
|
return 2;
|
2011-01-30 02:40:14 -08:00
|
|
|
|
2011-04-11 06:44:01 -07:00
|
|
|
/* We want to show it. */
|
|
|
|
c->par->visible = 1;
|
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
/* Check if we need to skip this paragraph because it's already layouted
|
|
|
|
* correctly, and mark handled nodes as dirty. */
|
|
|
|
c->par->line_no = c->line_no;
|
2011-04-07 06:13:38 -07:00
|
|
|
if (c->par->text_node && !c->calc_only)
|
2011-04-07 04:24:15 -07:00
|
|
|
{
|
|
|
|
/* Skip this paragraph if width is the same, there is no ellipsis
|
|
|
|
* and we aren't just calculating. */
|
|
|
|
if (!c->par->text_node->new && !c->par->text_node->dirty &&
|
2011-04-07 06:13:38 -07:00
|
|
|
!c->width_changed && c->par->lines &&
|
2011-04-07 04:24:15 -07:00
|
|
|
!c->o->have_ellipsis)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Line *ln;
|
|
|
|
/* Update c->line_no */
|
|
|
|
ln = (Evas_Object_Textblock_Line *)
|
|
|
|
EINA_INLIST_GET(c->par->lines)->last;
|
|
|
|
if (ln)
|
|
|
|
c->line_no = c->par->line_no + ln->line_no + 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
c->par->text_node->dirty = EINA_FALSE;
|
|
|
|
c->par->text_node->new = EINA_FALSE;
|
2011-04-11 08:37:06 -07:00
|
|
|
|
|
|
|
/* Merge back and clear the paragraph */
|
|
|
|
{
|
|
|
|
Eina_List *itr, *itr_next;
|
|
|
|
Evas_Object_Textblock_Item *it, *prev_it = NULL;
|
|
|
|
_paragraph_clear(c->obj, c->par);
|
|
|
|
EINA_LIST_FOREACH_SAFE(c->par->logical_items, itr, itr_next, it)
|
|
|
|
{
|
|
|
|
if (it->merge && prev_it &&
|
|
|
|
(prev_it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
|
|
|
|
(it->type == EVAS_TEXTBLOCK_ITEM_TEXT))
|
|
|
|
{
|
|
|
|
_layout_item_merge_and_free(c, _ITEM_TEXT(prev_it),
|
|
|
|
_ITEM_TEXT(it));
|
|
|
|
c->par->logical_items =
|
|
|
|
eina_list_remove_list(c->par->logical_items, itr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prev_it = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-07 04:24:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
c->y = c->par->y;
|
|
|
|
|
2011-01-30 02:40:53 -08:00
|
|
|
it = _ITEM(eina_list_data_get(c->par->logical_items));
|
|
|
|
_layout_line_new(c, it->format);
|
2011-01-30 02:40:30 -08:00
|
|
|
/* We walk on our own because we want to be able to add items from
|
|
|
|
* inside the list and then walk them on the next iteration. */
|
|
|
|
for (i = c->par->logical_items ; i ; )
|
|
|
|
{
|
|
|
|
int adv_line = 0;
|
|
|
|
int redo_item = 0;
|
|
|
|
it = _ITEM(eina_list_data_get(i));
|
2011-04-03 02:14:03 -07:00
|
|
|
/* Skip visually deleted items - only if it's a real calc.
|
|
|
|
* In the calc only case we want to take them into account */
|
|
|
|
if (!c->calc_only && it->visually_deleted)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
|
|
|
i = eina_list_next(i);
|
|
|
|
continue;
|
|
|
|
}
|
2011-01-30 02:45:34 -08:00
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
|
2011-01-30 02:45:34 -08:00
|
|
|
/* Check if we need to wrap, i.e the text is bigger than the width */
|
2011-01-30 02:40:30 -08:00
|
|
|
if ((c->w >= 0) &&
|
2011-03-29 06:52:35 -07:00
|
|
|
((c->x + it->w) >
|
2011-01-30 02:40:30 -08:00
|
|
|
(c->w - c->o->style_pad.l - c->o->style_pad.r -
|
|
|
|
c->marginl - c->marginr)))
|
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
/* Handle ellipsis here */
|
|
|
|
if ((it->format->ellipsis == 1.0) && (c->h >= 0) &&
|
|
|
|
(2 * it->h + c->y >
|
|
|
|
c->h - c->o->style_pad.t - c->o->style_pad.b))
|
2011-01-30 02:40:14 -08:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ellip_ti, *last_ti;
|
|
|
|
Evas_Object_Textblock_Item *last_it;
|
|
|
|
Evas_Coord save_cx;
|
|
|
|
int wrap;
|
|
|
|
ellip_ti = _layout_ellipsis_item_new(c, it);
|
|
|
|
last_it = it;
|
|
|
|
last_ti = _ITEM_TEXT(it);
|
|
|
|
|
|
|
|
save_cx = c->x;
|
|
|
|
c->w -= ellip_ti->parent.w;
|
|
|
|
do
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
wrap = _layout_text_cutoff_get(c, last_it->format,
|
|
|
|
last_ti);
|
2011-04-13 01:36:57 -07:00
|
|
|
if ((wrap > 0) && !IS_AT_END(last_ti, (size_t) wrap))
|
2011-01-30 02:45:45 -08:00
|
|
|
{
|
2011-02-14 01:37:49 -08:00
|
|
|
_layout_item_text_split_strip_white(c, last_ti, i,
|
2011-01-30 02:45:45 -08:00
|
|
|
wrap);
|
|
|
|
}
|
|
|
|
else if (wrap == 0)
|
|
|
|
{
|
|
|
|
if (!c->ln->items)
|
|
|
|
break;
|
|
|
|
/* We haven't added it yet at this point */
|
|
|
|
if (_ITEM(last_ti) != it)
|
|
|
|
{
|
|
|
|
last_it =
|
|
|
|
_ITEM(EINA_INLIST_GET(last_it)->prev);
|
|
|
|
c->ln->items = _ITEM(eina_inlist_remove(
|
|
|
|
EINA_INLIST_GET(c->ln->items),
|
|
|
|
EINA_INLIST_GET(_ITEM(last_ti))));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last_it =
|
|
|
|
_ITEM(EINA_INLIST_GET(c->ln->items)->last);
|
|
|
|
}
|
|
|
|
last_ti = _ITEM_TEXT(last_it);
|
|
|
|
if (last_it)
|
|
|
|
{
|
|
|
|
c->x -= last_it->adv;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
2011-01-30 02:45:45 -08:00
|
|
|
while (last_it && (wrap == 0));
|
|
|
|
c->x = save_cx;
|
|
|
|
c->w += ellip_ti->parent.w;
|
|
|
|
/* If we should add this item, do it */
|
|
|
|
if (last_it == it)
|
|
|
|
{
|
|
|
|
c->ln->items = (Evas_Object_Textblock_Item *)
|
|
|
|
eina_inlist_append(EINA_INLIST_GET(c->ln->items),
|
|
|
|
EINA_INLIST_GET(it));
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
fi = _ITEM_FORMAT(it);
|
|
|
|
fi->y = c->y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c->ln->items = (Evas_Object_Textblock_Item *)
|
|
|
|
eina_inlist_append(EINA_INLIST_GET(c->ln->items),
|
|
|
|
EINA_INLIST_GET(_ITEM(ellip_ti)));
|
|
|
|
c->ln->ellip_ti = ellip_ti;
|
|
|
|
_layout_line_finalize(c, ellip_ti->parent.format);
|
|
|
|
|
2011-05-05 04:06:06 -07:00
|
|
|
ret = 1;
|
|
|
|
goto end;
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
2011-01-30 02:45:45 -08:00
|
|
|
else if (it->format->wrap_word || it->format->wrap_char ||
|
|
|
|
it->format->wrap_mixed)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
/* Don't wrap if it's the only item */
|
|
|
|
if (c->ln->items)
|
|
|
|
{
|
|
|
|
/*FIXME: I should handle tabs correctly, i.e like
|
|
|
|
* spaces */
|
|
|
|
_layout_line_advance(c, it->format);
|
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
2011-01-30 02:45:45 -08:00
|
|
|
else
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
2011-01-30 02:45:45 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
|
|
|
|
int wrap;
|
2011-05-05 06:38:09 -07:00
|
|
|
size_t line_start;
|
2011-01-30 02:45:45 -08:00
|
|
|
|
2011-05-05 04:06:06 -07:00
|
|
|
#ifdef HAVE_LINEBREAK
|
|
|
|
/* If we haven't calculated the linebreaks yet,
|
|
|
|
* do */
|
|
|
|
if (!line_breaks)
|
|
|
|
{
|
|
|
|
size_t len =
|
|
|
|
eina_ustrbuf_length_get(it->text_node->unicode);
|
|
|
|
line_breaks = malloc(len);
|
|
|
|
/* Only relevant in those cases */
|
|
|
|
if (it->format->wrap_word || it->format->wrap_mixed)
|
|
|
|
{
|
|
|
|
set_linebreaks_utf32((const utf32_t *)
|
|
|
|
eina_ustrbuf_string_get(
|
|
|
|
it->text_node->unicode),
|
|
|
|
len, "", line_breaks);
|
|
|
|
/* FIXME: "" should be text_props language */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2011-05-05 06:38:09 -07:00
|
|
|
if (c->ln->items)
|
|
|
|
line_start = c->ln->items->text_pos;
|
|
|
|
else
|
|
|
|
line_start = ti->parent.text_pos;
|
2011-05-05 04:06:06 -07:00
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
adv_line = 1;
|
|
|
|
if (it->format->wrap_word)
|
2011-05-05 04:06:06 -07:00
|
|
|
wrap = _layout_get_wordwrap(c, it->format, ti,
|
2011-05-05 06:38:09 -07:00
|
|
|
line_start, line_breaks);
|
2011-01-30 02:45:45 -08:00
|
|
|
else if (it->format->wrap_char)
|
2011-05-05 04:06:06 -07:00
|
|
|
wrap = _layout_get_charwrap(c, it->format, ti,
|
2011-05-05 06:38:09 -07:00
|
|
|
line_start, line_breaks);
|
2011-01-30 02:45:45 -08:00
|
|
|
else if (it->format->wrap_mixed)
|
2011-05-05 04:06:06 -07:00
|
|
|
wrap = _layout_get_mixedwrap(c, it->format, ti,
|
2011-05-05 06:38:09 -07:00
|
|
|
line_start, line_breaks);
|
2011-01-30 02:45:45 -08:00
|
|
|
else
|
|
|
|
wrap = -1;
|
|
|
|
|
2011-05-05 06:38:09 -07:00
|
|
|
if (wrap > 0)
|
|
|
|
{
|
|
|
|
if ((size_t) wrap < ti->parent.text_pos)
|
|
|
|
wrap = 0;
|
|
|
|
else
|
|
|
|
wrap -= ti->parent.text_pos;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
if (wrap > 0)
|
|
|
|
{
|
2011-02-14 01:37:49 -08:00
|
|
|
_layout_item_text_split_strip_white(c, ti, i, wrap);
|
2011-01-30 02:45:45 -08:00
|
|
|
}
|
|
|
|
else if (wrap == 0)
|
|
|
|
{
|
|
|
|
/* Should wrap before the item */
|
|
|
|
adv_line = 0;
|
|
|
|
redo_item = 1;
|
|
|
|
_layout_line_advance(c, it->format);
|
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
|
|
|
if (!redo_item)
|
2011-01-30 02:40:14 -08:00
|
|
|
{
|
2011-01-30 02:40:30 -08:00
|
|
|
c->ln->items = (Evas_Object_Textblock_Item *)
|
|
|
|
eina_inlist_append(EINA_INLIST_GET(c->ln->items),
|
|
|
|
EINA_INLIST_GET(it));
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
fi = _ITEM_FORMAT(it);
|
|
|
|
fi->y = c->y;
|
2011-04-07 08:25:19 -07:00
|
|
|
/* If it's a newline, and we are not in newline compat
|
|
|
|
* mode, or we are in newline compat mode, and this is
|
|
|
|
* not used as a paragraph separator, advance */
|
|
|
|
if (fi->item && _IS_LINE_SEPARATOR(fi->item) &&
|
|
|
|
(!c->o->newline_is_ps ||
|
|
|
|
eina_list_next(i)))
|
2011-01-30 02:40:30 -08:00
|
|
|
{
|
|
|
|
adv_line = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c->x += it->adv;
|
|
|
|
i = eina_list_next(i);
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
if (adv_line)
|
2011-01-30 02:40:53 -08:00
|
|
|
{
|
|
|
|
/* Each line is according to the first item in it, and here
|
|
|
|
* i is already the next item (or the current if we redo it) */
|
|
|
|
if (i)
|
|
|
|
{
|
|
|
|
it = _ITEM(eina_list_data_get(i));
|
|
|
|
}
|
2011-01-30 02:41:18 -08:00
|
|
|
_layout_line_advance(c, it->format);
|
2011-01-30 02:40:53 -08:00
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
if (c->ln->items)
|
2011-01-30 02:40:53 -08:00
|
|
|
{
|
2011-01-30 02:41:18 -08:00
|
|
|
/* Here 'it' is the last format used */
|
|
|
|
_layout_line_finalize(c, it->format);
|
2011-01-30 02:40:53 -08:00
|
|
|
}
|
2011-05-05 04:06:06 -07:00
|
|
|
|
|
|
|
end:
|
|
|
|
#ifdef HAVE_LINEBREAK
|
|
|
|
if (line_breaks)
|
|
|
|
free(line_breaks);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create the layout from the nodes.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - NOT NULL.
|
2011-04-03 02:14:03 -07:00
|
|
|
* @param calc_only true if should only calc sizes false if should also create the layout.. It assumes native size is being calculated, doesn't support formatted size atm.
|
2010-09-21 08:39:26 -07:00
|
|
|
* @param w the object's w, -1 means no wrapping (i.e infinite size)
|
|
|
|
* @param h the object's h, -1 means inifinte size.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @param w_ret the object's calculated w.
|
|
|
|
* @param h_ret the object's calculated h.
|
|
|
|
*/
|
2005-08-20 01:01:59 -07:00
|
|
|
static void
|
2008-02-08 14:35:19 -08:00
|
|
|
_layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret)
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2005-08-20 01:01:59 -07:00
|
|
|
Ctxt ctxt, *c;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock_Format *fmt = NULL;
|
|
|
|
int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0;
|
2005-08-11 06:50:37 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
/* setup context */
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
c = &ctxt;
|
2008-02-08 14:35:19 -08:00
|
|
|
c->obj = (Evas_Object *)obj;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->o = o;
|
2010-08-09 09:24:17 -07:00
|
|
|
c->paragraphs = c->par = NULL;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->format_stack = NULL;
|
|
|
|
c->x = c->y = 0;
|
|
|
|
c->w = w;
|
|
|
|
c->h = h;
|
|
|
|
c->wmax = c->hmax = 0;
|
2010-03-04 08:22:28 -08:00
|
|
|
c->maxascent = c->maxdescent = 0;
|
2005-08-20 01:01:59 -07:00
|
|
|
c->marginl = c->marginr = 0;
|
|
|
|
c->have_underline = 0;
|
|
|
|
c->have_underline2 = 0;
|
|
|
|
c->underline_extend = 0;
|
|
|
|
c->line_no = 0;
|
|
|
|
c->align = 0.0;
|
2010-08-11 00:23:48 -07:00
|
|
|
c->align_auto = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
c->ln = NULL;
|
2011-04-03 02:14:03 -07:00
|
|
|
c->calc_only = !!calc_only;
|
2011-04-07 04:24:15 -07:00
|
|
|
c->width_changed = (obj->cur.geometry.w != o->last_w);
|
2011-01-30 02:41:13 -08:00
|
|
|
|
2011-04-27 05:41:26 -07:00
|
|
|
/* Mark text nodes as dirty if format have changed. */
|
|
|
|
if (c->o->format_changed)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *fnode = c->o->format_nodes;
|
|
|
|
Evas_Object_Textblock_Node_Text *start_n = NULL;
|
|
|
|
int balance = 0;
|
|
|
|
while (fnode)
|
|
|
|
{
|
|
|
|
if (fnode->new)
|
|
|
|
{
|
|
|
|
const char *fstr = eina_strbuf_string_get(fnode->format);
|
|
|
|
/* balance < 0 means we gave up and everything should be
|
|
|
|
* invalidated */
|
|
|
|
if (*fstr == '+')
|
|
|
|
{
|
|
|
|
balance++;
|
|
|
|
if (balance == 1)
|
|
|
|
start_n = fnode->text_node;
|
|
|
|
}
|
|
|
|
else if (*fstr == '-')
|
|
|
|
{
|
|
|
|
balance--;
|
|
|
|
if (balance == 0)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *f_tnode =
|
|
|
|
fnode->text_node;
|
|
|
|
while (start_n)
|
|
|
|
{
|
|
|
|
start_n->dirty = EINA_TRUE;
|
|
|
|
if (start_n == f_tnode)
|
|
|
|
break;
|
|
|
|
start_n =
|
|
|
|
_NODE_TEXT(EINA_INLIST_GET(start_n)->next);
|
|
|
|
}
|
|
|
|
start_n = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!fnode->visible)
|
|
|
|
balance = -1;
|
|
|
|
|
|
|
|
if (balance < 0)
|
|
|
|
{
|
|
|
|
/* if we don't already have a starting point, use the
|
|
|
|
* current paragraph. */
|
|
|
|
if (!start_n)
|
|
|
|
start_n = fnode->text_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (balance != 0)
|
|
|
|
{
|
|
|
|
while (start_n)
|
|
|
|
{
|
|
|
|
start_n->dirty = EINA_TRUE;
|
|
|
|
start_n = _NODE_TEXT(EINA_INLIST_GET(start_n)->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:41:13 -08:00
|
|
|
/* Start of logical layout creation */
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
/* setup default base style */
|
|
|
|
if ((c->o->style) && (c->o->style->default_tag))
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt = _layout_format_push(c, NULL);
|
|
|
|
_format_fill(c->obj, fmt, c->o->style->default_tag);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2005-10-14 21:42:46 -07:00
|
|
|
if (!fmt)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (w_ret) *w_ret = 0;
|
|
|
|
if (h_ret) *h_ret = 0;
|
|
|
|
return;
|
2005-10-14 21:42:46 -07:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2011-01-30 02:41:42 -08:00
|
|
|
if (o->content_changed)
|
2010-03-12 02:49:39 -08:00
|
|
|
{
|
2011-04-07 04:24:15 -07:00
|
|
|
c->par = c->paragraphs = o->paragraphs;
|
2011-01-30 02:43:26 -08:00
|
|
|
/* Go through all the text nodes to create the logical layout */
|
2011-01-30 02:41:42 -08:00
|
|
|
EINA_INLIST_FOREACH(c->o->text_nodes, n)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2011-01-30 02:41:42 -08:00
|
|
|
Evas_Object_Textblock_Node_Format *fnode;
|
|
|
|
size_t start;
|
|
|
|
int off;
|
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
/* If it's not a new paragraph, either update it or skip it.
|
|
|
|
* Remove all the paragraphs that were deleted */
|
|
|
|
if (!n->new)
|
|
|
|
{
|
|
|
|
/* Remove all the deleted paragraphs at this point */
|
|
|
|
while (c->par->text_node != n)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *tmp_par =
|
|
|
|
(Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->par));
|
|
|
|
_paragraph_free(obj, c->par);
|
2011-04-07 04:24:11 -07:00
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
c->par = tmp_par;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If it's dirty, remove and recreate, if it's clean,
|
|
|
|
* skip to the next. */
|
|
|
|
if (n->dirty)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *prev_par = c->par;
|
|
|
|
|
|
|
|
_layout_paragraph_new(c, n, EINA_TRUE);
|
|
|
|
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(prev_par));
|
|
|
|
_paragraph_free(obj, prev_par);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c->par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
|
|
|
|
/* Update the format stack according to the node's
|
|
|
|
* formats */
|
|
|
|
fnode = n->format_node;
|
|
|
|
while (fnode && (fnode->text_node == n))
|
|
|
|
{
|
|
|
|
_layout_do_format(obj, c, &fmt, fnode,
|
|
|
|
&style_pad_l, &style_pad_r,
|
2011-04-07 07:25:48 -07:00
|
|
|
&style_pad_t, &style_pad_b, EINA_FALSE);
|
2011-04-07 04:24:15 -07:00
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2011-04-07 07:01:31 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If it's a new paragraph, just add it. */
|
|
|
|
_layout_paragraph_new(c, n, EINA_FALSE);
|
|
|
|
}
|
2011-01-30 02:41:42 -08:00
|
|
|
|
2011-04-14 05:13:20 -07:00
|
|
|
#ifdef BIDI_SUPPORT
|
2011-04-14 08:34:01 -07:00
|
|
|
_layout_update_bidi_props(c->o, c->par);
|
2011-04-14 05:13:20 -07:00
|
|
|
#endif
|
|
|
|
|
2011-01-30 02:41:42 -08:00
|
|
|
/* For each text node to thorugh all of it's format nodes
|
|
|
|
* append text from the start to the offset of the next format
|
2011-04-14 05:13:20 -07:00
|
|
|
* using the last format got. if needed it also creates format
|
|
|
|
* items this is the core algorithm of the layout mechanism.
|
2011-01-30 02:41:42 -08:00
|
|
|
* Skip the unicode replacement chars when there are because
|
|
|
|
* we don't want to print them. */
|
|
|
|
fnode = n->format_node;
|
|
|
|
start = off = 0;
|
|
|
|
while (fnode && (fnode->text_node == n))
|
2010-04-25 04:35:41 -07:00
|
|
|
{
|
2011-01-30 02:41:42 -08:00
|
|
|
off += fnode->offset;
|
|
|
|
/* No need to skip on the first run, or a non-visible one */
|
|
|
|
_layout_text_append(c, fmt, n, start, off, o->repch);
|
|
|
|
_layout_do_format(obj, c, &fmt, fnode, &style_pad_l,
|
2011-04-07 07:25:48 -07:00
|
|
|
&style_pad_r, &style_pad_t, &style_pad_b, EINA_TRUE);
|
2011-01-30 02:41:42 -08:00
|
|
|
if ((c->have_underline2) || (c->have_underline))
|
|
|
|
{
|
|
|
|
if (style_pad_b < c->underline_extend)
|
|
|
|
style_pad_b = c->underline_extend;
|
|
|
|
c->have_underline = 0;
|
|
|
|
c->have_underline2 = 0;
|
|
|
|
c->underline_extend = 0;
|
|
|
|
}
|
|
|
|
start += off;
|
|
|
|
if (fnode->visible)
|
|
|
|
{
|
|
|
|
off = -1;
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
off = 0;
|
|
|
|
}
|
2011-04-27 05:41:26 -07:00
|
|
|
fnode->new = EINA_FALSE;
|
2011-01-30 02:41:42 -08:00
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
2010-04-25 04:35:41 -07:00
|
|
|
}
|
2011-01-30 02:41:42 -08:00
|
|
|
_layout_text_append(c, fmt, n, start, -1, o->repch);
|
2011-04-07 04:24:15 -07:00
|
|
|
c->par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete the rest of the layout paragraphs */
|
|
|
|
while (c->par)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *tmp_par =
|
|
|
|
(Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->par));
|
|
|
|
_paragraph_free(obj, c->par);
|
|
|
|
|
|
|
|
c->par = tmp_par;
|
2011-01-30 02:41:42 -08:00
|
|
|
}
|
2011-01-30 02:43:26 -08:00
|
|
|
o->paragraphs = c->paragraphs;
|
2011-04-07 04:24:15 -07:00
|
|
|
c->par = NULL;
|
2011-01-30 02:41:42 -08:00
|
|
|
}
|
2011-04-07 04:24:15 -07:00
|
|
|
|
|
|
|
c->paragraphs = o->paragraphs;
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:42:35 -08:00
|
|
|
/* If there are no paragraphs, create the minimum needed,
|
|
|
|
* if the last paragraph has no lines/text, create that as well */
|
2011-01-30 02:41:42 -08:00
|
|
|
if (!c->paragraphs)
|
|
|
|
{
|
2011-04-07 04:24:15 -07:00
|
|
|
_layout_paragraph_new(c, NULL, EINA_TRUE);
|
2011-01-30 02:44:48 -08:00
|
|
|
o->paragraphs = c->paragraphs;
|
2011-01-30 02:42:35 -08:00
|
|
|
}
|
|
|
|
c->par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->paragraphs)->last;
|
|
|
|
if (!c->par->logical_items)
|
|
|
|
{
|
2011-01-30 02:41:42 -08:00
|
|
|
_layout_text_append(c, fmt, NULL, 0, 0, NULL);
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:43:26 -08:00
|
|
|
/* In the case of calc only, we copy the items and the paragraphs,
|
|
|
|
* but because we don't change OT_DATA we can use it, just copy the item
|
|
|
|
* and ref */
|
|
|
|
if (calc_only)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *orig_pars, *par;
|
|
|
|
Eina_List *itr;
|
|
|
|
orig_pars = c->paragraphs;
|
|
|
|
c->paragraphs = NULL;
|
|
|
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(orig_pars), par)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
c->par = malloc(sizeof(Evas_Object_Textblock_Paragraph));
|
|
|
|
memcpy(c->par, par, sizeof(Evas_Object_Textblock_Paragraph));
|
|
|
|
/* Both of these should not be copied */
|
|
|
|
c->par->lines = NULL;
|
|
|
|
c->par->logical_items = NULL;
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_append(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->par));
|
|
|
|
|
|
|
|
/* Copy all the items */
|
|
|
|
EINA_LIST_FOREACH(par->logical_items, itr, it)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *new_it;
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
new_it = malloc(sizeof(Evas_Object_Textblock_Text_Item));
|
|
|
|
memcpy(new_it, it,
|
|
|
|
sizeof(Evas_Object_Textblock_Text_Item));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_it = malloc(
|
|
|
|
sizeof(Evas_Object_Textblock_Format_Item));
|
|
|
|
memcpy(new_it, it,
|
|
|
|
sizeof(Evas_Object_Textblock_Format_Item));
|
|
|
|
}
|
|
|
|
c->par->logical_items =
|
|
|
|
eina_list_append(c->par->logical_items, new_it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:41:13 -08:00
|
|
|
/* End of logical layout creation */
|
|
|
|
|
|
|
|
/* Start of visual layout creation */
|
2011-01-30 02:40:14 -08:00
|
|
|
{
|
2011-04-12 00:13:33 -07:00
|
|
|
Evas_Object_Textblock_Paragraph *last_vis_par = NULL;
|
|
|
|
|
2011-04-06 08:51:14 -07:00
|
|
|
EINA_INLIST_FOREACH(c->paragraphs, c->par)
|
2011-01-30 02:40:14 -08:00
|
|
|
{
|
|
|
|
_layout_update_par(c);
|
2011-04-07 04:24:15 -07:00
|
|
|
|
2011-01-30 02:45:45 -08:00
|
|
|
/* Break if we should stop here. */
|
|
|
|
if (_layout_visualize_par(c))
|
2011-04-11 06:44:01 -07:00
|
|
|
{
|
2011-04-12 00:13:33 -07:00
|
|
|
last_vis_par = c->par;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark all the rest of the paragraphs as invisible */
|
|
|
|
if (c->par)
|
|
|
|
{
|
|
|
|
c->par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
while (c->par)
|
|
|
|
{
|
|
|
|
c->par->visible = 0;
|
2011-04-11 06:44:01 -07:00
|
|
|
c->par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->par)->next;
|
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
2011-04-12 00:13:33 -07:00
|
|
|
|
|
|
|
/* Get the last visible paragraph in the layout */
|
|
|
|
if (!last_vis_par && c->paragraphs)
|
|
|
|
last_vis_par = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(c->paragraphs)->last;
|
|
|
|
|
|
|
|
if (last_vis_par)
|
|
|
|
c->hmax = last_vis_par->y + last_vis_par->h;
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
|
|
|
|
2010-07-28 05:00:41 -07:00
|
|
|
/* Clean the rest of the format stack */
|
2005-08-20 01:01:59 -07:00
|
|
|
while (c->format_stack)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt = c->format_stack->data;
|
|
|
|
c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack);
|
|
|
|
_format_unref_free(c->obj, fmt);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (w_ret) *w_ret = c->wmax;
|
|
|
|
if (h_ret) *h_ret = c->hmax;
|
2011-01-30 02:41:42 -08:00
|
|
|
|
2011-03-29 07:14:29 -07:00
|
|
|
/* Vertically align the textblock */
|
2011-03-30 05:26:07 -07:00
|
|
|
if ((o->valign > 0.0) && (c->h > c->hmax))
|
2011-03-29 07:14:29 -07:00
|
|
|
{
|
2011-03-30 05:58:09 -07:00
|
|
|
Evas_Coord adjustment = (c->h - c->hmax) * o->valign;
|
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
|
|
|
EINA_INLIST_FOREACH(c->paragraphs, par)
|
2011-03-29 07:14:29 -07:00
|
|
|
{
|
2011-03-30 05:58:09 -07:00
|
|
|
par->y += adjustment;
|
2011-03-29 07:14:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if ((o->style_pad.l != style_pad_l) || (o->style_pad.r != style_pad_r) ||
|
2011-01-15 22:20:26 -08:00
|
|
|
(o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b))
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
o->style_pad.l = style_pad_l;
|
|
|
|
o->style_pad.r = style_pad_r;
|
|
|
|
o->style_pad.t = style_pad_t;
|
|
|
|
o->style_pad.b = style_pad_b;
|
2011-01-30 02:43:26 -08:00
|
|
|
if (!calc_only)
|
|
|
|
{
|
|
|
|
_paragraphs_clear(obj, c->paragraphs);
|
|
|
|
}
|
2011-01-30 02:41:42 -08:00
|
|
|
_layout(obj, calc_only, w, h, w_ret, h_ret);
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2011-01-30 02:43:26 -08:00
|
|
|
|
|
|
|
if (calc_only)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
|
|
|
while (c->paragraphs)
|
|
|
|
{
|
|
|
|
Eina_List *itr, *itrn;
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
par = c->paragraphs;
|
2011-01-30 02:45:40 -08:00
|
|
|
/* free all the items */
|
2011-01-30 02:43:26 -08:00
|
|
|
EINA_LIST_FOREACH_SAFE(par->logical_items, itr, itrn, it)
|
|
|
|
{
|
|
|
|
par->logical_items =
|
|
|
|
eina_list_remove_list(par->logical_items, itr);
|
|
|
|
free(it);
|
|
|
|
}
|
|
|
|
c->paragraphs = (Evas_Object_Textblock_Paragraph *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
|
|
|
|
EINA_INLIST_GET(c->paragraphs));
|
2011-01-30 02:45:40 -08:00
|
|
|
_paragraph_clear(obj, par);
|
2011-01-30 02:43:26 -08:00
|
|
|
free(par);
|
|
|
|
}
|
|
|
|
}
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2010-09-21 08:39:26 -07:00
|
|
|
/*
|
|
|
|
* @internal
|
|
|
|
* Relayout the object according to current object size.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - NOT NULL.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2005-08-11 06:50:37 -07:00
|
|
|
static void
|
2008-02-08 14:35:19 -08:00
|
|
|
_relayout(const Evas_Object *obj)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-03-30 03:38:02 -07:00
|
|
|
o->have_ellipsis = 0;
|
2009-09-03 22:13:19 -07:00
|
|
|
_layout(obj,
|
2010-08-09 09:24:17 -07:00
|
|
|
0,
|
|
|
|
obj->cur.geometry.w, obj->cur.geometry.h,
|
|
|
|
&o->formatted.w, &o->formatted.h);
|
2005-08-27 23:41:54 -07:00
|
|
|
o->formatted.valid = 1;
|
2005-08-20 01:01:59 -07:00
|
|
|
o->last_w = obj->cur.geometry.w;
|
2011-03-30 03:31:29 -07:00
|
|
|
o->last_h = obj->cur.geometry.h;
|
2005-08-20 01:01:59 -07:00
|
|
|
o->changed = 0;
|
2011-01-30 02:40:36 -08:00
|
|
|
o->content_changed = 0;
|
2011-04-27 05:41:26 -07:00
|
|
|
o->format_changed = EINA_FALSE;
|
2005-08-27 23:41:54 -07:00
|
|
|
o->redraw = 1;
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Find the layout item and line that match the text node and position passed.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - NOT NULL.
|
|
|
|
* @param n the text node - Not null.
|
|
|
|
* @param pos the position to look for - valid.
|
|
|
|
* @param[out] lnr the line found - not null.
|
2011-01-30 02:31:22 -08:00
|
|
|
* @param[out] tir the item found - not null.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @see _find_layout_format_item_line_match()
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
static void
|
2011-01-30 02:31:58 -08:00
|
|
|
_find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Text *n, int pos, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2011-01-30 02:39:58 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
2005-08-20 22:13:49 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2008-10-17 04:23:18 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!o->formatted.valid) _relayout(obj);
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par)
|
2008-10-16 07:18:50 -07:00
|
|
|
{
|
2011-01-30 02:39:58 -08:00
|
|
|
if (par->text_node == n)
|
|
|
|
{
|
|
|
|
found_par = par;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found_par)
|
|
|
|
{
|
|
|
|
EINA_INLIST_FOREACH(found_par->lines, ln)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
Evas_Object_Textblock_Line *lnn;
|
2011-01-30 02:31:58 -08:00
|
|
|
|
2011-01-30 02:39:47 -08:00
|
|
|
lnn = (Evas_Object_Textblock_Line *)(((Eina_Inlist *)ln)->next);
|
|
|
|
EINA_INLIST_FOREACH(ln->items, it)
|
|
|
|
{
|
2011-01-30 02:39:58 -08:00
|
|
|
/* FIXME: p should be size_t, same goes for pos */
|
|
|
|
int p = (int) it->text_pos;
|
2011-01-30 02:31:16 -08:00
|
|
|
|
2011-01-30 02:39:58 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ti =
|
|
|
|
_ITEM_TEXT(it);
|
2005-08-20 22:13:49 -07:00
|
|
|
|
2011-02-14 05:09:41 -08:00
|
|
|
p += (int) ti->text_props.text_len;
|
2011-01-30 02:39:58 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
}
|
2011-01-30 02:39:47 -08:00
|
|
|
|
2011-01-30 02:39:58 -08:00
|
|
|
if (((pos >= (int) it->text_pos) && (pos < p)))
|
|
|
|
{
|
|
|
|
*lnr = ln;
|
|
|
|
*itr = it;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (p == pos)
|
|
|
|
{
|
|
|
|
*lnr = ln;
|
|
|
|
*itr = it;
|
2011-01-30 02:31:58 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Return the line number 'line'.
|
|
|
|
*
|
|
|
|
* @param obj the evas object - NOT NULL.
|
|
|
|
* @param line the line to find
|
|
|
|
* @return the line of line number or NULL if no line found.
|
|
|
|
*/
|
2005-08-20 22:13:49 -07:00
|
|
|
static Evas_Object_Textblock_Line *
|
2008-02-08 14:35:19 -08:00
|
|
|
_find_layout_line_num(const Evas_Object *obj, int line)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2011-01-30 02:39:52 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par, *prev_par = NULL;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
2005-08-20 22:13:49 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2011-01-30 02:39:52 -08:00
|
|
|
if (prev_par && (prev_par->line_no <= line) && (line < par->line_no))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev_par = par;
|
|
|
|
}
|
|
|
|
if (prev_par)
|
|
|
|
{
|
|
|
|
EINA_INLIST_FOREACH(prev_par->lines, ln)
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
|
|
|
if (ln->par->line_no + ln->line_no == line) return ln;
|
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI Evas_Object *
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_add(Evas *e)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
Evas_Object *obj;
|
|
|
|
|
|
|
|
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
|
|
|
|
return NULL;
|
|
|
|
MAGIC_CHECK_END();
|
2010-04-29 10:35:47 -07:00
|
|
|
obj = evas_object_new(e);
|
2005-08-20 22:13:49 -07:00
|
|
|
evas_object_textblock_init(obj);
|
|
|
|
evas_object_inject(obj, e);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI Evas_Textblock_Style *
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_style_new(void)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
Evas_Textblock_Style *ts;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
ts = calloc(1, sizeof(Evas_Textblock_Style));
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_style_free(Evas_Textblock_Style *ts)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
if (!ts) return;
|
|
|
|
if (ts->objects)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
ts->delete_me = 1;
|
|
|
|
return;
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
_style_clear(ts);
|
|
|
|
free(ts);
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2008-10-21 09:31:05 -07:00
|
|
|
Eina_List *l;
|
|
|
|
Evas_Object *obj;
|
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
if (!ts) return;
|
2011-02-24 00:43:38 -08:00
|
|
|
/* If the style wasn't really changed, abort. */
|
|
|
|
if ((!ts->style_text && !text) ||
|
|
|
|
(ts->style_text && text && !strcmp(text, ts->style_text)))
|
|
|
|
return;
|
2008-10-15 02:58:17 -07:00
|
|
|
|
2008-10-21 09:31:05 -07:00
|
|
|
EINA_LIST_FOREACH(ts->objects, l, obj)
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2008-10-21 09:31:05 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2011-04-07 04:24:15 -07:00
|
|
|
_evas_textblock_invalidate_all(o);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-02-24 00:43:34 -08:00
|
|
|
_style_replace(ts, text);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
if (ts->style_text)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
// format MUST be KEY='VALUE'[KEY='VALUE']...
|
2011-02-24 00:43:34 -08:00
|
|
|
const char *p;
|
|
|
|
const char *key_start, *key_stop, *val_start, *val_stop;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
key_start = key_stop = val_start = val_stop = NULL;
|
|
|
|
p = ts->style_text;
|
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
if (!key_start)
|
|
|
|
{
|
|
|
|
if (!isspace(*p))
|
|
|
|
key_start = p;
|
|
|
|
}
|
|
|
|
else if (!key_stop)
|
|
|
|
{
|
|
|
|
if ((*p == '=') || (isspace(*p)))
|
|
|
|
key_stop = p;
|
|
|
|
}
|
|
|
|
else if (!val_start)
|
|
|
|
{
|
|
|
|
if (((*p) == '\'') && (*(p + 1)))
|
|
|
|
val_start = p + 1;
|
|
|
|
}
|
|
|
|
else if (!val_stop)
|
|
|
|
{
|
|
|
|
if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\'))
|
|
|
|
val_stop = p;
|
|
|
|
}
|
|
|
|
if ((key_start) && (key_stop) && (val_start) && (val_stop))
|
|
|
|
{
|
|
|
|
char *tags, *replaces;
|
|
|
|
Evas_Object_Style_Tag *tag;
|
|
|
|
size_t tag_len = key_stop - key_start;
|
|
|
|
size_t replace_len = val_stop - val_start;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
tags = malloc(tag_len + 1);
|
|
|
|
if (tags)
|
|
|
|
{
|
|
|
|
memcpy(tags, key_start, tag_len);
|
|
|
|
tags[tag_len] = 0;
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
replaces = malloc(replace_len + 1);
|
|
|
|
if (replaces)
|
|
|
|
{
|
|
|
|
memcpy(replaces, val_start, replace_len);
|
|
|
|
replaces[replace_len] = 0;
|
|
|
|
}
|
|
|
|
if ((tags) && (replaces))
|
|
|
|
{
|
|
|
|
if (!strcmp(tags, "DEFAULT"))
|
|
|
|
{
|
|
|
|
ts->default_tag = replaces;
|
|
|
|
free(tags);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tag = calloc(1, sizeof(Evas_Object_Style_Tag));
|
|
|
|
if (tag)
|
|
|
|
{
|
|
|
|
tag->tag = tags;
|
|
|
|
tag->replace = replaces;
|
|
|
|
tag->tag_len = tag_len;
|
|
|
|
tag->replace_len = replace_len;
|
|
|
|
ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free(tags);
|
|
|
|
free(replaces);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tags) free(tags);
|
|
|
|
if (replaces) free(replaces);
|
|
|
|
}
|
|
|
|
key_start = key_stop = val_start = val_stop = NULL;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI const char *
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_style_get(const Evas_Textblock_Style *ts)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
if (!ts) return NULL;
|
|
|
|
return ts->style_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* textblock styles */
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_style_set(Evas_Object *obj, Evas_Textblock_Style *ts)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (ts == o->style) return;
|
|
|
|
if ((ts) && (ts->delete_me)) return;
|
2011-01-30 02:45:51 -08:00
|
|
|
if (o->style)
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2011-01-30 02:45:51 -08:00
|
|
|
Evas_Textblock_Style *old_ts;
|
|
|
|
if (o->markup_text)
|
2008-11-15 05:57:37 -08:00
|
|
|
{
|
|
|
|
free(o->markup_text);
|
|
|
|
o->markup_text = NULL;
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
old_ts = o->style;
|
|
|
|
old_ts->objects = eina_list_remove(old_ts->objects, obj);
|
|
|
|
if ((old_ts->delete_me) && (!old_ts->objects))
|
|
|
|
evas_textblock_style_free(old_ts);
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
if (ts)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
ts->objects = eina_list_append(ts->objects, obj);
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
2011-01-30 02:45:51 -08:00
|
|
|
o->style = ts;
|
2010-02-25 08:31:00 -08:00
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
|
|
|
_evas_textblock_invalidate_all(o);
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI const Evas_Textblock_Style *
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_object_textblock_style_get(const Evas_Object *obj)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
return o->style;
|
|
|
|
}
|
|
|
|
|
2008-10-22 01:57:30 -07:00
|
|
|
EAPI void
|
|
|
|
evas_object_textblock_replace_char_set(Evas_Object *obj, const char *ch)
|
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (o->repch) eina_stringshare_del(o->repch);
|
|
|
|
if (ch) o->repch = eina_stringshare_add(ch);
|
|
|
|
else o->repch = NULL;
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2011-04-07 04:24:15 -07:00
|
|
|
_evas_textblock_invalidate_all(o);
|
2008-10-22 01:57:30 -07:00
|
|
|
}
|
|
|
|
|
2011-02-14 06:17:12 -08:00
|
|
|
EAPI void
|
|
|
|
evas_object_textblock_newline_mode_set(Evas_Object *obj, Eina_Bool mode)
|
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (o->newline_is_ps == mode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
o->newline_is_ps = mode;
|
2011-03-30 05:08:50 -07:00
|
|
|
/* FIXME: Should recreate all the textnodes... For now, it's just
|
|
|
|
* for new text inserted. */
|
2011-02-14 06:17:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_object_textblock_newline_mode_get(const Evas_Object *obj)
|
|
|
|
{
|
2011-02-14 06:44:47 -08:00
|
|
|
TB_HEAD_RETURN(EINA_FALSE);
|
2011-02-14 06:17:12 -08:00
|
|
|
return o->newline_is_ps;
|
|
|
|
}
|
|
|
|
|
2011-03-30 03:31:29 -07:00
|
|
|
EAPI void
|
|
|
|
evas_object_textblock_valign_set(Evas_Object *obj, double align)
|
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (align < 0.0) align = 0.0;
|
|
|
|
else if (align > 1.0) align = 1.0;
|
|
|
|
if (o->valign == align) return;
|
|
|
|
o->valign = align;
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2011-03-30 03:31:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI double
|
|
|
|
evas_object_textblock_valign_get(const Evas_Object *obj)
|
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(0.0);
|
|
|
|
return o->valign;
|
|
|
|
}
|
|
|
|
|
2011-04-14 08:34:01 -07:00
|
|
|
EAPI void
|
|
|
|
evas_object_textblock_bidi_delimiters_set(Evas_Object *obj, const char *delim)
|
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
eina_stringshare_replace(&o->bidi_delimiters, delim);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI const char *
|
|
|
|
evas_object_textblock_bidi_delimiters_get(const Evas_Object *obj)
|
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
return o->bidi_delimiters;
|
|
|
|
}
|
|
|
|
|
2008-10-22 01:57:30 -07:00
|
|
|
EAPI const char *
|
|
|
|
evas_object_textblock_replace_char_get(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
return o->repch;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Advance p_buff to point after the end of the string. It's used with the
|
|
|
|
* @ref escaped_strings[] variable.
|
|
|
|
*
|
|
|
|
* @param p_buff the pointer to the current string.
|
|
|
|
*/
|
2009-12-21 11:07:51 -08:00
|
|
|
static inline void
|
2010-07-28 05:00:41 -07:00
|
|
|
_escaped_advance_after_end_of_string(const char **p_buf)
|
2009-12-21 11:07:51 -08:00
|
|
|
{
|
|
|
|
while (**p_buf != 0) (*p_buf)++;
|
|
|
|
(*p_buf)++;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Advance p_buff to point after the end of the string. It's used with the
|
|
|
|
* @ref escaped_strings[] variable. Also chec if matches.
|
|
|
|
* FIXME: doc.
|
|
|
|
*
|
|
|
|
* @param p_buff the pointer to the current string.
|
|
|
|
*/
|
2009-12-21 11:07:51 -08:00
|
|
|
static inline int
|
2010-07-28 05:00:41 -07:00
|
|
|
_escaped_is_eq_and_advance(const char *s, const char *s_end,
|
2010-08-09 09:24:17 -07:00
|
|
|
const char **p_m, const char *m_end)
|
2009-12-21 11:07:51 -08:00
|
|
|
{
|
|
|
|
for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (*s != **p_m)
|
|
|
|
{
|
|
|
|
_escaped_advance_after_end_of_string(p_m);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-12-21 11:07:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*p_m < m_end)
|
2010-07-28 05:00:41 -07:00
|
|
|
_escaped_advance_after_end_of_string(p_m);
|
2009-12-21 11:07:51 -08:00
|
|
|
|
|
|
|
return s == s_end;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @param s the string to match
|
|
|
|
*/
|
2009-12-21 11:07:51 -08:00
|
|
|
static inline const char *
|
|
|
|
_escaped_char_match(const char *s, int *adv)
|
|
|
|
{
|
|
|
|
const char *map_itr, *map_end, *mc, *sc;
|
|
|
|
|
|
|
|
map_itr = escape_strings;
|
|
|
|
map_end = map_itr + sizeof(escape_strings);
|
|
|
|
|
|
|
|
while (map_itr < map_end)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *escape;
|
|
|
|
int match;
|
2009-12-21 11:07:51 -08:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
escape = map_itr;
|
|
|
|
_escaped_advance_after_end_of_string(&map_itr);
|
|
|
|
if (map_itr >= map_end) break;
|
2009-12-21 11:07:51 -08:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
mc = map_itr;
|
|
|
|
sc = s;
|
|
|
|
match = 1;
|
|
|
|
while ((*mc) && (*sc))
|
|
|
|
{
|
|
|
|
if ((unsigned char)*sc < (unsigned char)*mc) return NULL;
|
|
|
|
if (*sc != *mc) match = 0;
|
|
|
|
mc++;
|
|
|
|
sc++;
|
|
|
|
}
|
|
|
|
if (match)
|
|
|
|
{
|
|
|
|
*adv = mc - map_itr;
|
|
|
|
return escape;
|
|
|
|
}
|
|
|
|
_escaped_advance_after_end_of_string(&map_itr);
|
2009-12-21 11:07:51 -08:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* FIXME: TBD.
|
|
|
|
*
|
|
|
|
* @param s the string to match
|
|
|
|
*/
|
2009-12-21 11:07:51 -08:00
|
|
|
static inline const char *
|
|
|
|
_escaped_char_get(const char *s, const char *s_end)
|
|
|
|
{
|
|
|
|
const char *map_itr, *map_end;
|
|
|
|
|
|
|
|
map_itr = escape_strings;
|
|
|
|
map_end = map_itr + sizeof(escape_strings);
|
|
|
|
|
|
|
|
while (map_itr < map_end)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end))
|
|
|
|
return map_itr;
|
|
|
|
if (map_itr < map_end)
|
|
|
|
_escaped_advance_after_end_of_string(&map_itr);
|
2009-12-21 11:07:51 -08:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-21 21:44:22 -07:00
|
|
|
EAPI const char *
|
|
|
|
evas_textblock_escape_string_get(const char *escape)
|
|
|
|
{
|
|
|
|
/* & -> & */
|
|
|
|
return _escaped_char_get(escape, escape + strlen(escape));
|
|
|
|
}
|
|
|
|
|
2009-04-14 16:51:43 -07:00
|
|
|
EAPI const char *
|
|
|
|
evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end)
|
|
|
|
{
|
|
|
|
return _escaped_char_get(escape_start, escape_end);
|
|
|
|
}
|
|
|
|
|
2008-10-21 21:44:22 -07:00
|
|
|
EAPI const char *
|
|
|
|
evas_textblock_string_escape_get(const char *string, int *len_ret)
|
|
|
|
{
|
|
|
|
/* & -> & */
|
|
|
|
return _escaped_char_match(string, len_ret);
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Appends the escaped char beteewn s and s_end to the curosr
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param s the start of the string
|
|
|
|
* @param s_end the end of the string.
|
|
|
|
*/
|
2008-10-21 21:44:22 -07:00
|
|
|
static inline void
|
|
|
|
_append_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *s_end)
|
2008-10-21 21:44:22 -07:00
|
|
|
{
|
|
|
|
const char *escape;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2008-10-21 21:44:22 -07:00
|
|
|
escape = _escaped_char_get(s, s_end);
|
|
|
|
if (escape)
|
|
|
|
evas_textblock_cursor_text_append(cur, escape);
|
2007-07-20 15:30:12 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* prepends the escaped char beteewn s and s_end to the curosr
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param s the start of the string
|
|
|
|
* @param s_end the end of the string.
|
|
|
|
*/
|
|
|
|
static inline void
|
2008-10-16 02:17:37 -07:00
|
|
|
_prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
|
2010-08-09 09:24:17 -07:00
|
|
|
const char *s_end)
|
2008-10-16 02:17:37 -07:00
|
|
|
{
|
2008-10-26 20:12:59 -07:00
|
|
|
const char *escape;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2008-10-26 20:12:59 -07:00
|
|
|
escape = _escaped_char_get(s, s_end);
|
|
|
|
if (escape)
|
|
|
|
evas_textblock_cursor_text_prepend(cur, escape);
|
2008-10-16 02:17:37 -07:00
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
|
|
|
TB_HEAD();
|
2005-09-12 01:57:38 -07:00
|
|
|
if ((text != o->markup_text) && (o->markup_text))
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
free(o->markup_text);
|
|
|
|
o->markup_text = NULL;
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
|
|
|
_nodes_clear(obj);
|
|
|
|
if (!o->style)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (text != o->markup_text)
|
|
|
|
{
|
|
|
|
if (text) o->markup_text = strdup(text);
|
|
|
|
}
|
|
|
|
return;
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_first(o->cursor);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_object_textblock_text_markup_prepend(o->cursor, text);
|
2010-08-11 03:27:44 -07:00
|
|
|
/* Point all the cursors to the starrt */
|
2005-09-10 04:51:52 -07:00
|
|
|
{
|
2010-07-28 05:00:41 -07:00
|
|
|
Eina_List *l;
|
|
|
|
Evas_Textblock_Cursor *data;
|
2008-10-21 09:31:05 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_first(o->cursor);
|
2010-07-28 05:00:41 -07:00
|
|
|
EINA_LIST_FOREACH(o->cursors, l, data)
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_first(data);
|
2005-09-10 04:51:52 -07:00
|
|
|
}
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2008-10-16 02:17:37 -07:00
|
|
|
EAPI void
|
|
|
|
evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object *obj = cur->obj;
|
|
|
|
TB_HEAD();
|
2008-10-16 02:17:37 -07:00
|
|
|
if (text)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *s, *p;
|
|
|
|
char *tag_start, *tag_end, *esc_start, *esc_end;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
tag_start = tag_end = esc_start = esc_end = NULL;
|
|
|
|
p = (char *)text;
|
|
|
|
s = p;
|
|
|
|
/* This loop goes through all of the mark up text until it finds format
|
|
|
|
* tags, escape sequences or the terminating NULL. When it finds either
|
|
|
|
* of those, it appends the text found up until that point to the textblock
|
|
|
|
* proccesses whatever found. It repeats itself until the termainating
|
|
|
|
* NULL is reached. */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* If we got to the end of string or just finished/started tag
|
|
|
|
* or escape sequence handling. */
|
|
|
|
if ((*p == 0) ||
|
|
|
|
(tag_end) || (esc_end) ||
|
|
|
|
(tag_start) || (esc_start))
|
|
|
|
{
|
|
|
|
if (tag_end)
|
|
|
|
{
|
|
|
|
/* If we reached to a tag ending, analyze the tag */
|
|
|
|
char *ttag;
|
|
|
|
size_t ttag_len = tag_end - tag_start -1;
|
2008-10-16 02:17:37 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
ttag = malloc(ttag_len + 1);
|
|
|
|
if (ttag)
|
|
|
|
{
|
|
|
|
const char *match;
|
|
|
|
size_t replace_len;
|
|
|
|
|
|
|
|
memcpy(ttag, tag_start + 1, ttag_len);
|
|
|
|
ttag[ttag_len] = 0;
|
|
|
|
match = _style_match_tag(o->style, ttag, ttag_len, &replace_len);
|
|
|
|
if (match)
|
|
|
|
{
|
2011-04-10 00:27:07 -07:00
|
|
|
evas_textblock_cursor_format_prepend(cur, match);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *ttag2;
|
|
|
|
|
|
|
|
ttag2 = malloc(ttag_len + 2 + 1);
|
|
|
|
if (ttag2)
|
|
|
|
{
|
|
|
|
if (ttag[0] == '/')
|
|
|
|
{
|
|
|
|
strcpy(ttag2, "- ");
|
|
|
|
strcat(ttag2, ttag + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(ttag2, "+ ");
|
|
|
|
strcat(ttag2, ttag);
|
|
|
|
}
|
2011-04-10 00:27:07 -07:00
|
|
|
evas_textblock_cursor_format_prepend(cur, ttag2);
|
2010-08-09 09:24:17 -07:00
|
|
|
free(ttag2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(ttag);
|
|
|
|
}
|
|
|
|
tag_start = tag_end = NULL;
|
|
|
|
}
|
|
|
|
else if (esc_end)
|
|
|
|
{
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_escaped_char(cur, esc_start, esc_end);
|
2010-08-09 09:24:17 -07:00
|
|
|
esc_start = esc_end = NULL;
|
|
|
|
}
|
|
|
|
else if (*p == 0)
|
|
|
|
{
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_text_run(cur, s, p);
|
2010-08-09 09:24:17 -07:00
|
|
|
s = NULL;
|
|
|
|
}
|
|
|
|
if (*p == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*p == '<')
|
|
|
|
{
|
|
|
|
if (!esc_start)
|
|
|
|
{
|
|
|
|
/* Append the text prior to this to the textblock and mark
|
|
|
|
* the start of the tag */
|
|
|
|
tag_start = p;
|
|
|
|
tag_end = NULL;
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_text_run(cur, s, p);
|
2010-08-09 09:24:17 -07:00
|
|
|
s = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*p == '>')
|
|
|
|
{
|
|
|
|
if (tag_start)
|
|
|
|
{
|
|
|
|
tag_end = p;
|
|
|
|
s = p + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*p == '&')
|
|
|
|
{
|
|
|
|
if (!tag_start)
|
|
|
|
{
|
|
|
|
/* Append the text prior to this to the textblock and mark
|
|
|
|
* the start of the escape sequence */
|
|
|
|
esc_start = p;
|
|
|
|
esc_end = NULL;
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_text_run(cur, s, p);
|
2010-08-09 09:24:17 -07:00
|
|
|
s = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (*p == ';')
|
|
|
|
{
|
|
|
|
if (esc_start)
|
|
|
|
{
|
|
|
|
esc_end = p;
|
|
|
|
s = p + 1;
|
|
|
|
}
|
|
|
|
}
|
2010-08-16 01:36:08 -07:00
|
|
|
/* Unicode object replcament char */
|
|
|
|
else if (!strncmp("\xEF\xBF\xBC", p, 3))
|
|
|
|
{
|
|
|
|
/*FIXME: currently just remove them, maybe do something
|
|
|
|
* fancier in the future, atm it breaks if this char
|
|
|
|
* is inside <> */
|
2011-04-10 00:27:07 -07:00
|
|
|
_prepend_text_run(cur, s, p);
|
2010-08-26 06:04:13 -07:00
|
|
|
p += 2; /* it's also advanced later in this loop need +3
|
|
|
|
* in total*/
|
|
|
|
s = p + 1; /* One after the end of the replacement char */
|
2010-08-16 01:36:08 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* An helper function to markup get. Appends the format from fnode to the strbugf txt.
|
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param txt the strbuf to append to.
|
|
|
|
* @param fnode the format node to process.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_markup_get_format_append(Evas_Object_Textblock *o, Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode)
|
|
|
|
{
|
|
|
|
size_t replace_len;
|
|
|
|
size_t tag_len;
|
|
|
|
const char *tag;
|
|
|
|
const char *replace;
|
|
|
|
|
|
|
|
replace_len = eina_strbuf_length_get(fnode->format);
|
|
|
|
replace = eina_strbuf_string_get(fnode->format);
|
|
|
|
tag = _style_match_replace(o->style, replace, replace_len, &tag_len);
|
|
|
|
eina_strbuf_append_char(txt, '<');
|
|
|
|
if (tag)
|
|
|
|
{
|
|
|
|
eina_strbuf_append_length(txt, tag, tag_len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
int push = 0;
|
|
|
|
int pop = 0;
|
|
|
|
|
|
|
|
// FIXME: need to escape
|
|
|
|
s = eina_strbuf_string_get(fnode->format);
|
|
|
|
if (*s == '+') push = 1;
|
|
|
|
if (*s == '-') pop = 1;
|
|
|
|
while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
|
|
|
|
if (pop) eina_strbuf_append_char(txt, '/');
|
|
|
|
eina_strbuf_append(txt, s);
|
|
|
|
}
|
|
|
|
eina_strbuf_append_char(txt, '>');
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* An helper function to markup get. Appends the text in text.
|
|
|
|
*
|
|
|
|
* @param txt the strbuf to append to.
|
|
|
|
* @param text the text to process.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_markup_get_text_append(Eina_Strbuf *txt, const Eina_Unicode *text)
|
|
|
|
{
|
2011-02-16 08:00:17 -08:00
|
|
|
char *p = eina_unicode_unicode_to_utf8(text, NULL);
|
2010-08-09 09:24:17 -07:00
|
|
|
char *base = p;
|
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
const char *escape;
|
|
|
|
int adv;
|
|
|
|
|
|
|
|
escape = _escaped_char_match(p, &adv);
|
|
|
|
if (escape)
|
|
|
|
{
|
|
|
|
p += adv;
|
|
|
|
eina_strbuf_append(txt, escape);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(txt, *p);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(base);
|
|
|
|
}
|
|
|
|
EAPI const char *
|
|
|
|
evas_object_textblock_text_markup_get(const Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
Eina_Strbuf *txt = NULL;
|
2009-12-21 11:07:51 -08:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
TB_HEAD_RETURN(NULL);
|
2008-10-15 02:58:17 -07:00
|
|
|
if (o->markup_text) return(o->markup_text);
|
2010-02-06 12:41:53 -08:00
|
|
|
txt = eina_strbuf_new();
|
2010-08-09 09:24:17 -07:00
|
|
|
EINA_INLIST_FOREACH(o->text_nodes, n)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *fnode;
|
|
|
|
Eina_Unicode *text_base, *text;
|
|
|
|
int off;
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/* For each text node to thorugh all of it's format nodes
|
|
|
|
* append text from the start to the offset of the next format
|
|
|
|
* using the last format got. if needed it also creates format items
|
|
|
|
* this is the core algorithm of the layout mechanism.
|
|
|
|
* Skip the unicode replacement chars when there are because
|
|
|
|
* we don't want to print them. */
|
2010-08-09 09:24:17 -07:00
|
|
|
text_base = text =
|
2011-02-14 02:49:09 -08:00
|
|
|
eina_unicode_strndup(eina_ustrbuf_string_get(n->unicode),
|
|
|
|
eina_ustrbuf_length_get(n->unicode));
|
2010-08-09 09:24:17 -07:00
|
|
|
fnode = n->format_node;
|
|
|
|
off = 0;
|
|
|
|
while (fnode && (fnode->text_node == n))
|
|
|
|
{
|
|
|
|
Eina_Unicode tmp_ch;
|
|
|
|
off += fnode->offset;
|
|
|
|
/* No need to skip on the first run */
|
|
|
|
tmp_ch = text[off];
|
|
|
|
text[off] = 0; /* Null terminate the part of the string */
|
|
|
|
_markup_get_text_append(txt, text);
|
|
|
|
_markup_get_format_append(o, txt, fnode);
|
|
|
|
text[off] = tmp_ch; /* Restore the char */
|
|
|
|
text += off;
|
|
|
|
if (fnode->visible)
|
|
|
|
{
|
|
|
|
off = -1;
|
|
|
|
text++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
off = 0;
|
|
|
|
}
|
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
|
|
|
}
|
|
|
|
/* Add the rest, skip replacement */
|
|
|
|
_markup_get_text_append(txt, text);
|
|
|
|
free(text_base);
|
2009-12-21 11:07:51 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
|
2010-02-09 13:06:27 -08:00
|
|
|
o->markup_text = eina_strbuf_string_steal(txt);
|
2010-02-06 12:41:53 -08:00
|
|
|
eina_strbuf_free(txt);
|
2005-08-20 01:01:59 -07:00
|
|
|
return o->markup_text;
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
/* cursors */
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Merge the current node with the next, no need to remove PS, already
|
|
|
|
* not there.
|
|
|
|
*
|
|
|
|
* @param o the text block object.
|
|
|
|
* @param to merge into to.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_nodes_merge(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *to)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
Evas_Object_Textblock_Node_Format *pnode;
|
2010-08-25 07:37:52 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *from;
|
2010-08-09 09:24:17 -07:00
|
|
|
const Eina_Unicode *text;
|
|
|
|
int to_len, len;
|
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
if (!to) return;
|
|
|
|
from = _NODE_TEXT(EINA_INLIST_GET(to)->next);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
to_len = eina_ustrbuf_length_get(to->unicode);
|
|
|
|
text = eina_ustrbuf_string_get(from->unicode);
|
|
|
|
len = eina_ustrbuf_length_get(from->unicode);
|
|
|
|
eina_ustrbuf_append_length(to->unicode, text, len);
|
|
|
|
|
|
|
|
itr = from->format_node;
|
|
|
|
if (itr && (itr->text_node == from))
|
|
|
|
{
|
|
|
|
pnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->prev);
|
|
|
|
if (pnode && (pnode->text_node == to))
|
|
|
|
{
|
|
|
|
itr->offset += to_len - _evas_textblock_node_format_pos_get(pnode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
itr->offset += to_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (itr && (itr->text_node == from))
|
|
|
|
{
|
|
|
|
itr->text_node = to;
|
|
|
|
itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
|
|
|
|
}
|
|
|
|
if (!to->format_node || (to->format_node->text_node != to))
|
|
|
|
{
|
|
|
|
to->format_node = from->format_node;
|
|
|
|
}
|
|
|
|
|
2011-04-17 01:38:29 -07:00
|
|
|
/* When it comes to how we handle it, merging is like removing both nodes
|
|
|
|
* and creating a new one, se we need to do the needed cleanups. */
|
|
|
|
if (to->par)
|
|
|
|
to->par->text_node = NULL;
|
|
|
|
to->par = NULL;
|
|
|
|
|
|
|
|
to->new = EINA_TRUE;
|
|
|
|
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_set_node(o, from, to);
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_node_text_remove(o, from);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Merge the current node with the next, no need to remove PS, already
|
|
|
|
* not there.
|
|
|
|
*
|
|
|
|
* @param cur the cursor that points to the current node
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_evas_textblock_cursor_nodes_merge(Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *nnode;
|
|
|
|
Evas_Object_Textblock *o;
|
2010-08-11 03:27:44 -07:00
|
|
|
int len;
|
2011-01-14 00:47:32 -08:00
|
|
|
if (!cur) return;
|
2010-08-11 03:27:44 -07:00
|
|
|
|
|
|
|
len = eina_ustrbuf_length_get(cur->node->unicode);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next);
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_nodes_merge(o, cur->node);
|
|
|
|
_evas_textblock_cursors_update_offset(cur, nnode, 0, len);
|
|
|
|
_evas_textblock_cursors_set_node(o, nnode, cur->node);
|
2010-08-11 03:27:44 -07:00
|
|
|
if (nnode == o->cursor->node)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-11 03:27:44 -07:00
|
|
|
o->cursor->node = cur->node;
|
|
|
|
o->cursor->pos += len;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
2010-08-09 09:24:17 -07:00
|
|
|
* Return the format at a specific position.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param cur the cursor to the position.
|
2010-09-07 20:51:24 -07:00
|
|
|
* @return the format node at the specific position or NULL if not found.
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static Evas_Object_Textblock_Node_Format *
|
|
|
|
_evas_textblock_cursor_node_format_at_pos_get(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *node;
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
2010-08-16 03:46:56 -07:00
|
|
|
int position = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
if (!cur->node) return NULL;
|
|
|
|
|
|
|
|
node = cur->node->format_node;
|
|
|
|
if (!node) return NULL;
|
|
|
|
/* If there is no exclusive format node to this paragraph return the
|
|
|
|
* previous's node */
|
|
|
|
/* Find the main format node */
|
|
|
|
EINA_INLIST_FOREACH(node, itr)
|
|
|
|
{
|
|
|
|
if (itr->text_node != cur->node)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ((position + itr->offset) == cur->pos)
|
|
|
|
{
|
|
|
|
return itr;
|
|
|
|
}
|
|
|
|
position += itr->offset;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Return the last format node at the position of the format node n.
|
|
|
|
*
|
2010-09-07 20:51:24 -07:00
|
|
|
* @param n a format node at the position.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @return the last format node at the position of n.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static Evas_Object_Textblock_Node_Format *
|
|
|
|
_evas_textblock_node_format_last_at_off(const Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
const Evas_Object_Textblock_Node_Format *nnode;
|
2010-12-08 07:41:21 -08:00
|
|
|
const Evas_Object_Textblock_Node_Text *tnode;
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!n) return NULL;
|
|
|
|
nnode = n;
|
2010-12-08 07:41:21 -08:00
|
|
|
tnode = n->text_node;
|
2010-08-09 09:24:17 -07:00
|
|
|
do
|
|
|
|
{
|
|
|
|
n = nnode;
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
|
|
|
|
}
|
2010-12-08 07:41:21 -08:00
|
|
|
while (nnode && (nnode->text_node == tnode) && (nnode->offset == 0));
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
return (Evas_Object_Textblock_Node_Format *) n;
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns the visible format at a specific location.
|
|
|
|
*
|
|
|
|
* @param n a format at the specific position.
|
2010-09-07 20:51:24 -07:00
|
|
|
* @return the format node at the specific position or NULL if not found.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static Evas_Object_Textblock_Node_Format *
|
|
|
|
_evas_textblock_node_visible_at_pos_get(const Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
const Evas_Object_Textblock_Node_Format *nnode;
|
|
|
|
if (!n) return NULL;
|
2010-08-10 07:36:48 -07:00
|
|
|
/* The visible format is the last one, because it inserts a replacement
|
|
|
|
* char that advances the next formats. */
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
nnode = n;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
n = nnode;
|
|
|
|
if (n->visible) return (Evas_Object_Textblock_Node_Format *) n;
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
|
|
|
|
}
|
|
|
|
while (nnode && (nnode->offset == 0));
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
|
|
|
* Return the last format that applies to a specific cursor or at the specific
|
|
|
|
* position the cursor points to. This means either a cursor at or before the
|
|
|
|
* position of the cursor in the text node is returned or the previous's text
|
|
|
|
* node's format node.
|
|
|
|
*
|
2010-09-07 20:51:24 -07:00
|
|
|
* @param cur the position to look at.
|
2010-08-10 07:36:48 -07:00
|
|
|
* @return the format node found.
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static Evas_Object_Textblock_Node_Format *
|
|
|
|
_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *node, *pitr = NULL;
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
size_t position = 0;
|
|
|
|
|
|
|
|
if (!cur->node) return NULL;
|
|
|
|
|
|
|
|
node = cur->node->format_node;
|
|
|
|
if (!node) return NULL;
|
|
|
|
/* If there is no exclusive format node to this paragraph return the
|
|
|
|
* previous's node */
|
|
|
|
if (node->text_node != cur->node)
|
|
|
|
{
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
else if (node->offset > cur->pos)
|
|
|
|
{
|
|
|
|
return _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
|
|
|
|
}
|
|
|
|
/* Find the main format node */
|
|
|
|
pitr = _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
|
|
|
|
EINA_INLIST_FOREACH(node, itr)
|
|
|
|
{
|
|
|
|
if ((itr->text_node != cur->node) ||
|
|
|
|
((position + itr->offset) > cur->pos))
|
|
|
|
{
|
|
|
|
return pitr;
|
|
|
|
}
|
|
|
|
else if ((position + itr->offset) == cur->pos)
|
|
|
|
{
|
|
|
|
return itr;
|
|
|
|
}
|
|
|
|
pitr = itr;
|
|
|
|
position += itr->offset;
|
|
|
|
}
|
|
|
|
return pitr;
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2011-01-30 02:31:22 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Find the layout item and line that match the cursor.
|
|
|
|
*
|
|
|
|
* @param cur the cursor we are currently at. - NOT NULL.
|
|
|
|
* @param[out] lnr the line found - not null.
|
|
|
|
* @param[out] itr the item found - not null.
|
|
|
|
* @return EINA_TRUE if we matched the previous format, EINA_FALSE otherwise.
|
|
|
|
*/
|
|
|
|
static Eina_Bool
|
|
|
|
_find_layout_item_match(const Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
|
|
|
|
{
|
|
|
|
Evas_Textblock_Cursor cur2;
|
|
|
|
Eina_Bool previous_format = EINA_FALSE;
|
|
|
|
|
|
|
|
cur2.obj = cur->obj;
|
|
|
|
evas_textblock_cursor_copy(cur, &cur2);
|
|
|
|
if (cur2.pos > 0)
|
|
|
|
{
|
|
|
|
cur2.pos--;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:31:58 -08:00
|
|
|
if (_evas_textblock_cursor_is_at_the_end(cur) &&
|
2011-01-30 02:31:22 -08:00
|
|
|
evas_textblock_cursor_format_is_visible_get(&cur2))
|
|
|
|
{
|
2011-01-30 02:31:58 -08:00
|
|
|
_find_layout_item_line_match(cur2.obj, cur2.node, cur2.pos, lnr, itr);
|
2011-01-30 02:31:22 -08:00
|
|
|
previous_format = EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:31:58 -08:00
|
|
|
_find_layout_item_line_match(cur->obj, cur->node, cur->pos, lnr, itr);
|
2011-01-30 02:31:22 -08:00
|
|
|
}
|
|
|
|
return previous_format;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI const Evas_Textblock_Cursor *
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_object_textblock_cursor_get(const Evas_Object *obj)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
return o->cursor;
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI Evas_Textblock_Cursor *
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_cursor_new(Evas_Object *obj)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Textblock_Cursor *cur;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
cur = calloc(1, sizeof(Evas_Textblock_Cursor));
|
|
|
|
cur->obj = obj;
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->node = o->text_nodes;
|
2005-08-20 01:01:59 -07:00
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2008-10-21 09:31:05 -07:00
|
|
|
o->cursors = eina_list_append(o->cursors, cur);
|
2005-08-20 01:01:59 -07:00
|
|
|
return cur;
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_cursor_free(Evas_Textblock_Cursor *cur)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
if (!cur) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (cur == o->cursor) return;
|
2008-10-21 09:31:05 -07:00
|
|
|
o->cursors = eina_list_remove(o->cursors, cur);
|
2005-08-20 01:01:59 -07:00
|
|
|
free(cur);
|
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
2010-08-12 00:02:30 -07:00
|
|
|
if (!cur || !cur->node) return EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
if (evas_textblock_cursor_format_is_visible_get(cur)) return EINA_TRUE;
|
|
|
|
return (_evas_textblock_cursor_node_format_at_pos_get(cur)) ?
|
|
|
|
EINA_TRUE : EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI const Evas_Object_Textblock_Node_Format *
|
|
|
|
evas_textblock_node_format_first_get(const Evas_Object *obj)
|
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
return o->format_nodes;
|
|
|
|
}
|
|
|
|
EAPI const Evas_Object_Textblock_Node_Format *
|
|
|
|
evas_textblock_node_format_last_get(const Evas_Object *obj)
|
|
|
|
{
|
|
|
|
TB_HEAD_RETURN(NULL);
|
|
|
|
if (o->format_nodes)
|
|
|
|
{
|
|
|
|
return _NODE_FORMAT(EINA_INLIST_GET(o->format_nodes)->last);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI const Evas_Object_Textblock_Node_Format *
|
|
|
|
evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
return _NODE_FORMAT(EINA_INLIST_GET(n)->next);
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI const Evas_Object_Textblock_Node_Format *
|
|
|
|
evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
return _NODE_FORMAT(EINA_INLIST_GET(n)->prev);
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-09-20 02:44:48 -07:00
|
|
|
EAPI void
|
|
|
|
evas_textblock_node_format_remove_pair(Evas_Object *obj,
|
|
|
|
Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
2011-04-28 01:18:44 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *tnode1;
|
2010-09-20 02:44:48 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *fmt, *pnode;
|
|
|
|
int level;
|
|
|
|
TB_HEAD();
|
|
|
|
|
|
|
|
if (!n) return;
|
|
|
|
|
|
|
|
pnode = NULL;
|
|
|
|
fmt = n;
|
|
|
|
level = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
const char *fstr = eina_strbuf_string_get(fmt->format);
|
|
|
|
|
|
|
|
if (fstr && (*fstr == '+'))
|
|
|
|
{
|
|
|
|
level++;
|
|
|
|
}
|
|
|
|
else if (fstr && (*fstr == '-'))
|
|
|
|
{
|
|
|
|
level--;
|
|
|
|
}
|
|
|
|
|
|
|
|
pnode = fmt;
|
|
|
|
fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
|
|
|
|
}
|
|
|
|
while (fmt && (level > 0));
|
|
|
|
|
|
|
|
if (n->visible)
|
|
|
|
{
|
|
|
|
size_t index = _evas_textblock_node_format_pos_get(n);
|
|
|
|
const char *format = eina_strbuf_string_get(n->format);
|
|
|
|
Evas_Textblock_Cursor cur;
|
|
|
|
cur.obj = obj;
|
|
|
|
|
|
|
|
eina_ustrbuf_remove(n->text_node->unicode, index, index + 1);
|
2011-02-14 06:17:12 -08:00
|
|
|
if (format && _IS_PARAGRAPH_SEPARATOR(o, format))
|
2010-09-20 02:44:48 -07:00
|
|
|
{
|
|
|
|
evas_textblock_cursor_set_at_format(&cur, n);
|
|
|
|
_evas_textblock_cursor_nodes_merge(&cur);
|
|
|
|
}
|
|
|
|
_evas_textblock_cursors_update_offset(&cur, n->text_node, index, -1);
|
|
|
|
}
|
2011-04-28 01:18:44 -07:00
|
|
|
tnode1 = n->text_node;
|
2010-10-06 01:45:10 -07:00
|
|
|
_evas_textblock_node_format_remove(o, n, 0);
|
2010-09-20 02:44:48 -07:00
|
|
|
if (pnode && (pnode != n))
|
|
|
|
{
|
2011-04-28 01:18:44 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *tnode2;
|
|
|
|
tnode2 = pnode->text_node;
|
2010-10-06 01:45:10 -07:00
|
|
|
/* pnode can never be visible! (it's the closing format) */
|
2010-09-20 02:44:48 -07:00
|
|
|
_evas_textblock_node_format_remove(o, pnode, 0);
|
2011-04-28 01:18:44 -07:00
|
|
|
|
|
|
|
/* FIXME: Should be unified in the layout, for example, added to a list
|
|
|
|
* that checks this kind of removals. But until then, this is very fast
|
|
|
|
* and works. */
|
|
|
|
/* Mark all the text nodes in between the removed formats as dirty. */
|
|
|
|
while (tnode1)
|
|
|
|
{
|
|
|
|
tnode1->dirty = EINA_TRUE;
|
|
|
|
if (tnode1 == tnode2)
|
|
|
|
break;
|
|
|
|
tnode1 =
|
|
|
|
_NODE_TEXT(EINA_INLIST_GET(tnode1)->next);
|
|
|
|
}
|
2010-09-20 02:44:48 -07:00
|
|
|
}
|
2011-04-28 01:18:44 -07:00
|
|
|
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2010-09-20 02:44:48 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
if (!cur) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->node = o->text_nodes;
|
2005-08-20 01:01:59 -07:00
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *node;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (!cur) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
node = o->text_nodes;
|
|
|
|
if (node)
|
2005-08-13 06:43:20 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
node = _NODE_TEXT(EINA_INLIST_GET(node)->last);
|
|
|
|
cur->node = node;
|
2005-08-30 08:19:39 -07:00
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
evas_textblock_cursor_paragraph_char_last(cur);
|
2005-08-13 06:43:20 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
cur->node = NULL;
|
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
/* If there is a current text node, return the next text node (if exists)
|
|
|
|
* otherwise, just return False. */
|
|
|
|
if (cur->node)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *nnode;
|
|
|
|
nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next);
|
|
|
|
if (nnode)
|
|
|
|
{
|
|
|
|
cur->node = nnode;
|
|
|
|
cur->pos = 0;
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_FALSE;
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur)
|
2005-08-13 06:43:20 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *node;
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
/* If the current node is a text node, just get the prev if any,
|
|
|
|
* if it's a format, get the current text node out of the format and return
|
|
|
|
* the prev text node if any. */
|
|
|
|
node = cur->node;
|
|
|
|
/* If there is a current text node, return the prev text node
|
|
|
|
* (if exists) otherwise, just return False. */
|
|
|
|
if (node)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *pnode;
|
|
|
|
pnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->prev);
|
|
|
|
if (pnode)
|
|
|
|
{
|
|
|
|
cur->node = pnode;
|
|
|
|
evas_textblock_cursor_paragraph_char_last(cur);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2005-08-13 06:43:20 -07:00
|
|
|
}
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_FALSE;
|
2005-08-13 06:43:20 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI void
|
|
|
|
evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
if (!cur || !n) return;
|
|
|
|
cur->node = n->text_node;
|
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(n);
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur)
|
2005-08-13 06:43:20 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *node;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
/* 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_node_format_last_at_off(node);
|
|
|
|
if (!node)
|
|
|
|
{
|
|
|
|
if (cur->node->format_node)
|
|
|
|
{
|
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(node);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If there is a current text node, return the next format node (if exists)
|
|
|
|
* otherwise, just return False. */
|
|
|
|
else
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(node)->next);
|
|
|
|
if (nnode)
|
|
|
|
{
|
|
|
|
cur->node = nnode->text_node;
|
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(nnode);
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *node;
|
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
|
|
|
/* 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);
|
|
|
|
if (evas_textblock_cursor_is_format(cur))
|
|
|
|
{
|
|
|
|
if (node)
|
2010-03-11 06:29:25 -08:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(node);
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
2010-03-11 06:29:25 -08:00
|
|
|
}
|
2009-05-14 05:52:44 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
/* If there is a current text node, return the next text node (if exists)
|
|
|
|
* otherwise, just return False. */
|
|
|
|
if (node)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *pnode;
|
|
|
|
pnode = _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
|
|
|
|
if (pnode)
|
|
|
|
{
|
|
|
|
cur->node = pnode->text_node;
|
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(node);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EINA_FALSE;
|
2005-08-13 06:43:20 -07:00
|
|
|
}
|
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
|
2005-08-14 08:48:07 -07:00
|
|
|
{
|
2009-06-14 13:48:37 -07:00
|
|
|
int index;
|
2010-08-09 09:24:17 -07:00
|
|
|
const Eina_Unicode *text;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
index = cur->pos;
|
|
|
|
text = eina_ustrbuf_string_get(cur->node->unicode);
|
2011-04-13 01:36:57 -07:00
|
|
|
if (text[index]) index++;
|
2010-08-09 09:24:17 -07:00
|
|
|
/* Only allow pointing a null if it's the last paragraph.
|
|
|
|
* because we don't have a PS there. */
|
|
|
|
if (text[index])
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->pos = index;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!evas_textblock_cursor_paragraph_next(cur))
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
2011-01-24 18:56:14 -08:00
|
|
|
/* If we already were at the end, that means we don't have
|
|
|
|
* where to go next we should return FALSE */
|
|
|
|
if (cur->pos == (size_t) index)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->pos = index;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-24 18:56:14 -08:00
|
|
|
return EINA_TRUE;
|
2009-05-14 05:52:44 -07:00
|
|
|
}
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
|
|
|
|
|
|
|
if (cur->pos != 0)
|
2009-05-14 05:52:44 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
cur->pos--;
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_TRUE;
|
2009-05-14 05:52:44 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
return evas_textblock_cursor_paragraph_prev(cur);
|
2005-08-14 08:48:07 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur)
|
2005-08-14 08:48:07 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
if (!cur) return;
|
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-14 08:48:07 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur)
|
2005-08-14 08:48:07 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
int index;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (!cur) return;
|
|
|
|
if (!cur->node) return;
|
2010-08-16 02:44:50 -07:00
|
|
|
index = eina_ustrbuf_length_get(cur->node->unicode) - 1;
|
2011-02-22 01:31:19 -08:00
|
|
|
if (index >= 0)
|
|
|
|
cur->pos = index;
|
|
|
|
else
|
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-14 08:48:07 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln = NULL;
|
|
|
|
Evas_Object_Textblock_Item *it = NULL;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!cur) return;
|
|
|
|
if (!cur->node) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2010-08-29 02:13:48 -07:00
|
|
|
|
2011-01-30 02:31:22 -08:00
|
|
|
_find_layout_item_match(cur, &ln, &it);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!ln) return;
|
2011-01-30 02:31:08 -08:00
|
|
|
if (ln->items)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *i;
|
|
|
|
it = ln->items;
|
|
|
|
EINA_INLIST_FOREACH(ln->items, i)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
if (it->text_pos > i->text_pos)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
|
|
|
it = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-30 08:19:39 -07:00
|
|
|
if (it)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
cur->pos = it->text_pos;
|
|
|
|
cur->node = it->text_node;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln = NULL;
|
|
|
|
Evas_Object_Textblock_Item *it = NULL;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!cur) return;
|
|
|
|
if (!cur->node) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2011-01-30 02:31:22 -08:00
|
|
|
_find_layout_item_match(cur, &ln, &it);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!ln) return;
|
|
|
|
if (ln->items)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *i;
|
|
|
|
it = ln->items;
|
|
|
|
EINA_INLIST_FOREACH(ln->items, i)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
if (it->text_pos < i->text_pos)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
|
|
|
it = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-30 08:19:39 -07:00
|
|
|
if (it)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
size_t index;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
cur->node = it->text_node;
|
|
|
|
cur->pos = it->text_pos;
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
2011-02-14 05:09:41 -08:00
|
|
|
index = _ITEM_TEXT(it)->text_props.text_len - 1;
|
2011-04-13 01:36:57 -07:00
|
|
|
if (!IS_AT_END(_ITEM_TEXT(it), index)) index++;
|
2011-01-30 02:31:16 -08:00
|
|
|
cur->pos += index;
|
|
|
|
}
|
2011-01-30 02:40:14 -08:00
|
|
|
else if (!EINA_INLIST_GET(ln)->next && !EINA_INLIST_GET(ln->par)->next)
|
2010-08-29 02:13:48 -07:00
|
|
|
{
|
|
|
|
cur->pos++;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* checks if a format (as a string) is visible.
|
|
|
|
*
|
|
|
|
* @param the string.
|
|
|
|
* @return #EINA_TRUE if it represents a visible format #EINA_FALSE otherwise.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_evas_textblock_format_is_visible(const char *s)
|
|
|
|
{
|
|
|
|
const char *item;
|
2010-08-15 09:04:34 -07:00
|
|
|
Eina_Bool is_opener = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-12-11 01:00:13 -08:00
|
|
|
if (!s) return EINA_FALSE;
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (s[0] == '+' || s[0] == '-')
|
|
|
|
{
|
2010-08-15 09:04:34 -07:00
|
|
|
is_opener = (s[0] == '+') ? EINA_TRUE : EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
s++;
|
|
|
|
}
|
|
|
|
while ((item = _format_parse(&s)))
|
|
|
|
{
|
2011-04-27 07:59:22 -07:00
|
|
|
int itlen = s - item;
|
2010-08-15 09:04:34 -07:00
|
|
|
/* 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 */
|
2011-04-27 07:59:22 -07:00
|
|
|
if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) ||
|
|
|
|
(!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) ||
|
|
|
|
!strncmp(item, "ps", itlen) ||
|
|
|
|
(!strncmp(item, "item", itlen) && is_opener))
|
2010-08-09 09:24:17 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the cursor to the position of where the fmt points to.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param cur the cursor to update.
|
|
|
|
* @param fmt the format to set according to.
|
|
|
|
* @return nothing.
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
2010-08-12 02:31:43 -07:00
|
|
|
static void __UNUSED__
|
2010-08-09 09:24:17 -07:00
|
|
|
_evas_textblock_cursor_node_text_at_format(Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Node_Format *fmt)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *text;
|
|
|
|
Evas_Object_Textblock_Node_Format *base_format;
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
size_t position = 0;
|
|
|
|
|
|
|
|
if (!cur || !fmt) return;
|
|
|
|
/* Find the main format node */
|
|
|
|
text = fmt->text_node;
|
|
|
|
cur->node = text;
|
|
|
|
base_format = text->format_node;
|
|
|
|
EINA_INLIST_FOREACH(base_format, itr)
|
|
|
|
{
|
|
|
|
if (itr == fmt)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
position += itr->offset;
|
|
|
|
}
|
|
|
|
cur->pos = position;
|
|
|
|
|
|
|
|
}
|
2010-08-25 07:37:52 -07:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Remove pairs of + and - formats and also remove formats without + or -
|
2010-09-15 07:07:09 -07:00
|
|
|
* i.e formats that pair to themselves. Only removes invisible formats
|
|
|
|
* that pair themselves, if you want to remove invisible formats that pair
|
|
|
|
* themselves, please first change fmt->visible to EINA_FALSE.
|
2010-08-25 07:37:52 -07:00
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param fmt the current format.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_evas_textblock_node_format_remove_matching(Evas_Object_Textblock *o,
|
|
|
|
Evas_Object_Textblock_Node_Format *fmt)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *tnode;
|
|
|
|
Eina_List *formats = NULL;
|
2010-09-18 18:33:51 -07:00
|
|
|
size_t offset = 0;
|
2010-08-25 07:37:52 -07:00
|
|
|
|
|
|
|
if (!fmt) return;
|
|
|
|
|
|
|
|
tnode = fmt->text_node;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
|
|
|
const char *fstr = eina_strbuf_string_get(fmt->format);
|
|
|
|
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
|
|
|
|
if (nnode)
|
|
|
|
{
|
|
|
|
offset = nnode->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (fstr && (*fstr == '+'))
|
|
|
|
{
|
|
|
|
formats = eina_list_prepend(formats, fmt);
|
|
|
|
}
|
|
|
|
else if (fstr && (*fstr == '-'))
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *fnode;
|
|
|
|
fnode = eina_list_data_get(formats);
|
|
|
|
if (fnode)
|
|
|
|
{
|
|
|
|
formats = eina_list_remove(formats, fnode);
|
|
|
|
_evas_textblock_node_format_remove(o, fnode, 0);
|
|
|
|
_evas_textblock_node_format_remove(o, fmt, 0);
|
|
|
|
}
|
|
|
|
}
|
2010-09-15 07:07:09 -07:00
|
|
|
else if (!fmt->visible)
|
2010-08-25 07:37:52 -07:00
|
|
|
{
|
|
|
|
_evas_textblock_node_format_remove(o, fmt, 0);
|
|
|
|
}
|
|
|
|
fmt = nnode;
|
|
|
|
}
|
|
|
|
while (fmt && (offset == 0) && (fmt->text_node == tnode));
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
|
|
|
* Add the offset (may be negative) to the first node after fmt which is
|
|
|
|
* pointing to the text node tnode or to o->format_nodes if fmt is null
|
|
|
|
* and it points to tnode.
|
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param tnode the text node the format should point to.
|
|
|
|
* @param fmt the current format.
|
|
|
|
* @param offset the offest to add (may be negative).
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_evas_textblock_node_format_adjust_offset(Evas_Object_Textblock *o,
|
|
|
|
Evas_Object_Textblock_Node_Text *tnode,
|
|
|
|
Evas_Object_Textblock_Node_Format *fmt, int offset)
|
|
|
|
{
|
|
|
|
if (fmt)
|
|
|
|
{
|
|
|
|
fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fmt = o->format_nodes;
|
|
|
|
}
|
|
|
|
if (fmt && (tnode == fmt->text_node))
|
|
|
|
{
|
|
|
|
fmt->offset += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
|
|
|
* Removes a format node updating the offset of the next format node and the
|
|
|
|
* text nodes pointing to this node.
|
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param n the fromat node to remove
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static void
|
2010-08-18 05:29:20 -07:00
|
|
|
_evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visible_adjustment)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
/* Update the text nodes about the change */
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->next);
|
|
|
|
/* If there's a next node that belongs to the same text node
|
|
|
|
* and the curret node was the main one, advance the format node */
|
|
|
|
if (nnode && (nnode->text_node == n->text_node))
|
|
|
|
{
|
|
|
|
if (nnode->text_node->format_node == n)
|
|
|
|
{
|
|
|
|
nnode->text_node->format_node = nnode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *tnode;
|
|
|
|
/* If there's no next one update the text nodes */
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->prev);
|
|
|
|
tnode = n->text_node;
|
2010-08-25 07:37:52 -07:00
|
|
|
/* Even if it's not the current text_node's main node
|
|
|
|
* it can still be the next's. */
|
|
|
|
if (tnode && (tnode->format_node != n))
|
|
|
|
{
|
|
|
|
tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next);
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
while (tnode && (tnode->format_node == n))
|
|
|
|
{
|
|
|
|
tnode->format_node = nnode;
|
|
|
|
tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_evas_textblock_node_format_adjust_offset(o, n->text_node, n,
|
|
|
|
n->offset - visible_adjustment);
|
|
|
|
|
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_remove(
|
|
|
|
EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n)));
|
2011-01-12 07:27:53 -08:00
|
|
|
_evas_textblock_node_format_free(n);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
2010-08-25 07:37:52 -07:00
|
|
|
* Sets all the offsets of the format nodes between start and end in the text
|
2010-09-15 07:07:09 -07:00
|
|
|
* node n to 0 and sets visibility to EINA_FALSE.
|
2010-08-25 07:37:52 -07:00
|
|
|
* If end == -1 end means the end of the string.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
2010-08-25 07:37:52 -07:00
|
|
|
* @param n the text node the positinos refer to.
|
|
|
|
* @param start the start of where to delete from.
|
|
|
|
* @param end the end of the section to delete, if end == -1 it means the end of the string.
|
|
|
|
* @returns #EINA_TRUE if removed a PS, false otherwise.
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-25 07:37:52 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_evas_textblock_node_text_adjust_offsets_to_start(Evas_Object_Textblock *o,
|
|
|
|
Evas_Object_Textblock_Node_Text *n, size_t start, int end)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *last_node, *itr;
|
|
|
|
Evas_Object_Textblock_Node_Text *new_node;
|
|
|
|
int use_end = 1;
|
|
|
|
int delta = 0;
|
|
|
|
int first = 1;
|
|
|
|
int update_format_node;
|
|
|
|
size_t pos = 0;
|
2010-10-05 09:17:04 -07:00
|
|
|
int orig_end;
|
2010-08-10 01:34:47 -07:00
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
itr = n->format_node;
|
|
|
|
if (!itr || (itr->text_node != n)) return EINA_FALSE;
|
|
|
|
|
2010-10-05 09:17:04 -07:00
|
|
|
orig_end = end;
|
2010-08-25 07:37:52 -07:00
|
|
|
if ((end < 0) || ((size_t) end == eina_ustrbuf_length_get(n->unicode)))
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
use_end = 0;
|
|
|
|
}
|
2010-10-05 09:17:04 -07:00
|
|
|
else if (end > 0)
|
|
|
|
{
|
|
|
|
/* We don't want the last one */
|
|
|
|
end--;
|
|
|
|
}
|
2010-08-25 07:37:52 -07:00
|
|
|
|
|
|
|
/* If we are not removing the text node, all should stay in this text
|
|
|
|
* node, otherwise, everything should move to the previous node */
|
|
|
|
if ((start == 0) && !use_end)
|
|
|
|
{
|
|
|
|
new_node = _NODE_TEXT(EINA_INLIST_GET(n)->prev);
|
|
|
|
if (!new_node)
|
|
|
|
{
|
|
|
|
new_node = _NODE_TEXT(EINA_INLIST_GET(n)->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_node = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the first node after start */
|
|
|
|
while (itr && (itr->text_node == n))
|
|
|
|
{
|
|
|
|
pos += itr->offset;
|
|
|
|
if (pos >= start)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itr || (itr->text_node != n))
|
|
|
|
{
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
update_format_node = ((itr == n->format_node) && (new_node != n));
|
2010-10-05 09:17:04 -07:00
|
|
|
delta = orig_end - pos;
|
2010-08-25 07:37:52 -07:00
|
|
|
itr->offset -= pos - start;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
while (itr && (itr->text_node == n))
|
|
|
|
{
|
|
|
|
last_node = itr;
|
|
|
|
itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
|
|
|
|
|
|
|
|
if (!first)
|
|
|
|
{
|
|
|
|
pos += last_node->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* start is negative when this gets relevant */
|
|
|
|
if (use_end && (pos > (size_t) end))
|
|
|
|
{
|
|
|
|
last_node->offset -= delta;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-10-05 09:17:04 -07:00
|
|
|
delta = orig_end - pos;
|
2010-08-25 07:37:52 -07:00
|
|
|
if (!first)
|
|
|
|
{
|
|
|
|
last_node->offset = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
first = 0;
|
|
|
|
}
|
2010-10-05 09:17:01 -07:00
|
|
|
last_node->visible = EINA_FALSE;
|
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
if (!itr || (itr && (itr->text_node != n)))
|
|
|
|
{
|
|
|
|
/* Remove the PS, and return since it's the end of the node */
|
2011-02-14 06:17:12 -08:00
|
|
|
if (_IS_PARAGRAPH_SEPARATOR(o,
|
2010-08-25 07:37:52 -07:00
|
|
|
eina_strbuf_string_get(last_node->format)))
|
|
|
|
{
|
|
|
|
_evas_textblock_node_format_remove(o, last_node, 0);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
last_node->text_node = new_node;
|
|
|
|
if (update_format_node)
|
|
|
|
{
|
|
|
|
n->format_node = last_node;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-25 07:37:52 -07:00
|
|
|
|
|
|
|
return EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
2010-08-11 05:29:20 -07:00
|
|
|
* @internal
|
2010-08-10 07:36:48 -07:00
|
|
|
* Removes all the format nodes between start and end in the text node n.
|
|
|
|
* This function updates the offset of the next format node and the
|
|
|
|
* text nodes pointing to it. if end == -1 end means the end of the string.
|
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param n the text node the positinos refer to.
|
|
|
|
* @param start the start of where to delete from.
|
|
|
|
* @param end the end of the section to delete, if end == -1 it means the end of the string.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o,
|
|
|
|
Evas_Object_Textblock_Node_Text *n, int start, int end)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
int use_end = 1;
|
2010-08-18 05:29:20 -07:00
|
|
|
int offset = end - start;
|
2010-08-09 09:24:17 -07:00
|
|
|
itr = n->format_node;
|
2010-08-18 05:29:20 -07:00
|
|
|
|
2010-08-18 06:56:34 -07:00
|
|
|
if (itr)
|
|
|
|
start -= itr->offset;
|
2010-08-18 05:29:20 -07:00
|
|
|
if (offset < 0) offset = 0;
|
2010-10-05 09:17:01 -07:00
|
|
|
if (end < 0) use_end = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
while (itr && (itr->text_node == n))
|
|
|
|
{
|
2010-08-18 05:29:20 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
2010-08-18 08:27:37 -07:00
|
|
|
int tmp_offset = 0;
|
|
|
|
|
2010-08-18 05:29:20 -07:00
|
|
|
/* start is negative when this gets relevant */
|
2010-10-05 09:17:04 -07:00
|
|
|
if ((offset + start < 0) && use_end)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2010-08-18 05:29:20 -07:00
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
|
|
|
|
if (nnode)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-18 05:29:20 -07:00
|
|
|
tmp_offset = nnode->offset;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-18 05:29:20 -07:00
|
|
|
if (start <= 0)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-18 05:29:20 -07:00
|
|
|
/* Don't do visible adjustments because we are removing the visual
|
|
|
|
* chars anyway and taking those into account */
|
|
|
|
_evas_textblock_node_format_remove(o, itr, 0);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-18 05:29:20 -07:00
|
|
|
start -= tmp_offset;
|
|
|
|
itr = nnode;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-11 05:29:20 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns the first format in the range between start and end in the textblock
|
|
|
|
* n.
|
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param n the text node the positinos refer to.
|
|
|
|
* @param start the start of where to delete from.
|
|
|
|
* @param end the end of the section to delete, if end == -1 it means the end of the string.
|
|
|
|
*/
|
|
|
|
static Evas_Object_Textblock_Node_Format *
|
2010-08-18 06:56:34 -07:00
|
|
|
_evas_textblock_node_text_get_first_format_between(
|
2010-08-11 05:29:20 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n, int start, int end)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
int use_end = 1;
|
|
|
|
itr = n->format_node;
|
2010-08-16 01:52:18 -07:00
|
|
|
if (end < 0) use_end = 0;
|
2010-08-11 05:29:20 -07:00
|
|
|
while (itr && (itr->text_node == n))
|
|
|
|
{
|
|
|
|
start -= itr->offset;
|
|
|
|
end -= itr->offset;
|
|
|
|
if ((end <= 0) && use_end)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (start <= 0)
|
|
|
|
{
|
|
|
|
return itr;
|
|
|
|
}
|
|
|
|
itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-11-01 12:40:07 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* Removes a text node and the corresponding format nodes.
|
|
|
|
*
|
|
|
|
* @param o the textblock objec.t
|
|
|
|
* @param n the node to remove.
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n)
|
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_node_text_adjust_offsets_to_start(o, n, 0, -1);
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
o->text_nodes = _NODE_TEXT(eina_inlist_remove(
|
|
|
|
EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n)));
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_node_text_free(n);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
2010-08-09 09:24:17 -07:00
|
|
|
* Return the position where the formats starts at.
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param fmt the format to return the position of.
|
|
|
|
* @return the position of the format in the text node it points to.
|
2010-08-09 09:24:17 -07:00
|
|
|
*/
|
|
|
|
static size_t
|
|
|
|
_evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *text;
|
|
|
|
Evas_Object_Textblock_Node_Format *base_format;
|
|
|
|
Evas_Object_Textblock_Node_Format *itr;
|
|
|
|
size_t position = 0;
|
|
|
|
|
|
|
|
if (!fmt) return 0;
|
|
|
|
/* Find the main format node */
|
|
|
|
text = fmt->text_node;
|
|
|
|
base_format = text->format_node;
|
|
|
|
EINA_INLIST_FOREACH(base_format, itr)
|
|
|
|
{
|
|
|
|
if (itr == fmt)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
position += itr->offset;
|
|
|
|
}
|
|
|
|
return position + fmt->offset;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI int
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
2010-12-23 04:47:23 -08:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
size_t npos = 0;
|
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!cur) return -1;
|
2010-12-23 04:47:23 -08:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
n = o->text_nodes;
|
|
|
|
while (n != cur->node)
|
|
|
|
{
|
|
|
|
npos += eina_ustrbuf_length_get(n->unicode);
|
|
|
|
n = _NODE_TEXT(EINA_INLIST_GET(n)->next);
|
|
|
|
}
|
|
|
|
return npos + cur->pos;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2010-08-18 06:56:34 -07:00
|
|
|
evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int _pos)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
2010-12-23 04:47:23 -08:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
size_t pos;
|
2010-02-06 12:41:53 -08:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!cur) return;
|
2010-12-23 04:47:23 -08:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
|
2010-08-18 06:56:34 -07:00
|
|
|
if (_pos < 0)
|
|
|
|
{
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = (size_t) _pos;
|
|
|
|
}
|
|
|
|
|
2010-12-23 04:47:23 -08:00
|
|
|
n = o->text_nodes;
|
2010-12-26 04:01:21 -08:00
|
|
|
while (n && (pos >= eina_ustrbuf_length_get(n->unicode)))
|
2010-08-18 06:56:34 -07:00
|
|
|
{
|
2010-12-23 04:47:23 -08:00
|
|
|
pos -= eina_ustrbuf_length_get(n->unicode);
|
|
|
|
n = _NODE_TEXT(EINA_INLIST_GET(n)->next);
|
2010-08-18 06:56:34 -07:00
|
|
|
}
|
2010-12-23 04:47:23 -08:00
|
|
|
|
2010-12-26 04:01:21 -08:00
|
|
|
if (n)
|
|
|
|
{
|
|
|
|
cur->node = n;
|
|
|
|
cur->pos = pos;
|
|
|
|
}
|
2011-01-09 23:23:31 -08:00
|
|
|
else if (o->text_nodes)
|
2010-12-26 04:01:21 -08:00
|
|
|
{
|
2011-01-09 23:23:31 -08:00
|
|
|
/* In case we went pass the last node, we need to put the cursor
|
|
|
|
* at the absolute end. */
|
2010-12-26 04:01:21 -08:00
|
|
|
Evas_Object_Textblock_Node_Text *last_n;
|
|
|
|
|
|
|
|
last_n = _NODE_TEXT(EINA_INLIST_GET(o->text_nodes)->last);
|
2011-01-09 23:23:31 -08:00
|
|
|
pos = eina_ustrbuf_length_get(last_n->unicode);
|
2010-12-26 04:01:21 -08:00
|
|
|
|
2011-01-09 23:23:31 -08:00
|
|
|
cur->node = last_n;
|
|
|
|
cur->pos = pos;
|
2010-12-26 04:01:21 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln;
|
2005-09-02 08:27:09 -07:00
|
|
|
Evas_Object_Textblock_Item *it;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
2005-08-30 08:19:39 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
|
|
|
|
|
|
|
ln = _find_layout_line_num(cur->obj, line);
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!ln) return EINA_FALSE;
|
2005-09-02 08:27:09 -07:00
|
|
|
it = (Evas_Object_Textblock_Item *)ln->items;
|
|
|
|
if (it)
|
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
cur->pos = it->text_pos;
|
|
|
|
cur->node = it->text_node;
|
2005-09-02 08:27:09 -07:00
|
|
|
}
|
2010-03-14 05:24:42 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
cur->node = o->text_nodes;
|
2010-03-14 05:24:42 -07:00
|
|
|
}
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_TRUE;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI int
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
2008-10-17 04:23:18 -07:00
|
|
|
Eina_Inlist *l1, *l2;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!cur1) return 0;
|
2005-09-09 07:19:06 -07:00
|
|
|
if (!cur2) return 0;
|
2005-08-30 08:19:39 -07:00
|
|
|
if (cur1->obj != cur2->obj) return 0;
|
|
|
|
if ((!cur1->node) || (!cur2->node)) return 0;
|
|
|
|
if (cur1->node == cur2->node)
|
|
|
|
{
|
|
|
|
if (cur1->pos < cur2->pos) return -1; /* cur1 < cur2 */
|
|
|
|
else if (cur1->pos > cur2->pos) return 1; /* cur2 < cur1 */
|
2010-08-09 09:24:17 -07:00
|
|
|
return 0;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
2008-10-17 04:23:18 -07:00
|
|
|
for (l1 = EINA_INLIST_GET(cur1->node),
|
2009-05-14 05:52:44 -07:00
|
|
|
l2 = EINA_INLIST_GET(cur1->node); (l1) || (l2);)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
2008-10-17 04:23:18 -07:00
|
|
|
if (l1 == EINA_INLIST_GET(cur2->node)) return 1; /* cur2 < cur 1 */
|
|
|
|
else if (l2 == EINA_INLIST_GET(cur2->node)) return -1; /* cur1 < cur 2 */
|
2005-08-30 08:19:39 -07:00
|
|
|
else if (!l1) return -1; /* cur1 < cur 2 */
|
|
|
|
else if (!l2) return 1; /* cur2 < cur 1 */
|
2010-07-13 19:05:47 -07:00
|
|
|
l1 = l1->prev;
|
|
|
|
l2 = l2->next;
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest)
|
2005-08-30 08:19:39 -07:00
|
|
|
{
|
|
|
|
if (!cur) return;
|
|
|
|
if (!cur_dest) return;
|
|
|
|
if (cur->obj != cur_dest->obj) return;
|
|
|
|
cur_dest->pos = cur->pos;
|
|
|
|
cur_dest->node = cur->node;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-30 08:19:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
/* text controls */
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2010-08-25 07:37:52 -07:00
|
|
|
* Free a text node. Shouldn't be used usually, it's better to use
|
|
|
|
* @ref _evas_textblock_node_text_remove for most cases .
|
2010-08-10 07:36:48 -07:00
|
|
|
*
|
|
|
|
* @param n the text node to free
|
2010-08-25 07:37:52 -07:00
|
|
|
* @see _evas_textblock_node_text_remove
|
2010-08-10 07:36:48 -07:00
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n)
|
|
|
|
{
|
|
|
|
if (!n) return;
|
|
|
|
eina_ustrbuf_free(n->unicode);
|
|
|
|
if (n->utf8)
|
|
|
|
free(n->utf8);
|
2011-04-14 05:13:20 -07:00
|
|
|
if (n->par)
|
|
|
|
n->par->text_node = NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
free(n);
|
|
|
|
}
|
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create a new text node
|
|
|
|
*
|
|
|
|
* @return the new text node.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static Evas_Object_Textblock_Node_Text *
|
2010-08-10 07:36:48 -07:00
|
|
|
_evas_textblock_node_text_new(void)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
|
|
|
|
n = calloc(1, sizeof(Evas_Object_Textblock_Node_Text));
|
|
|
|
n->unicode = eina_ustrbuf_new();
|
2011-01-30 02:40:14 -08:00
|
|
|
/* We want to layout each paragraph at least once. */
|
|
|
|
n->dirty = EINA_TRUE;
|
2011-04-07 04:24:11 -07:00
|
|
|
n->new = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-11-01 12:40:07 -07:00
|
|
|
/**
|
2010-08-10 07:36:48 -07:00
|
|
|
* @internal
|
|
|
|
* Break a paragraph. This does not add a PS but only splits the paragraph
|
|
|
|
* where a ps was just added!
|
|
|
|
*
|
|
|
|
* @param cur the cursor to break at.
|
|
|
|
* @param fnode the format node of the PS just added.
|
2008-06-28 03:55:58 -07:00
|
|
|
* @return Returns no value.
|
|
|
|
*/
|
2010-08-09 09:24:17 -07:00
|
|
|
static void
|
|
|
|
_evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
|
|
|
|
Evas_Object_Textblock_Node_Format *fnode)
|
2005-08-14 08:48:07 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (!cur) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2005-09-10 04:51:52 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
n = _evas_textblock_node_text_new();
|
|
|
|
o->text_nodes = _NODE_TEXT(eina_inlist_append_relative(
|
|
|
|
EINA_INLIST_GET(o->text_nodes),
|
|
|
|
EINA_INLIST_GET(n),
|
|
|
|
EINA_INLIST_GET(cur->node)));
|
|
|
|
/* Handle text and format changes. */
|
|
|
|
if (cur->node)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
|
|
|
size_t len, start;
|
|
|
|
const Eina_Unicode *text;
|
|
|
|
|
|
|
|
/* 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->text_node = n;
|
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-03-13 22:38:58 -08:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
n->format_node = fnode;
|
2010-03-13 22:38:58 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
/* cur->pos now points to the PS, move after. */
|
|
|
|
start = cur->pos + 1;
|
|
|
|
text = eina_ustrbuf_string_get(cur->node->unicode);
|
|
|
|
len = eina_ustrbuf_length_get(cur->node->unicode) - start;
|
|
|
|
eina_ustrbuf_append_length(n->unicode, text + start, len);
|
|
|
|
eina_ustrbuf_remove(cur->node->unicode, start, start + len);
|
2011-04-27 05:41:26 -07:00
|
|
|
cur->node->dirty = EINA_TRUE;
|
2010-07-28 05:00:41 -07:00
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
else
|
2010-07-28 05:00:41 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *fnode;
|
|
|
|
fnode = o->format_nodes;
|
|
|
|
if (fnode)
|
|
|
|
{
|
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->last);
|
|
|
|
}
|
|
|
|
n->format_node = fnode;
|
2010-03-13 22:38:58 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
|
2010-08-11 03:27:44 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
2010-08-12 07:59:42 -07:00
|
|
|
* Set the node and offset of all the curs after cur.
|
|
|
|
*
|
|
|
|
* @param cur the cursor.
|
|
|
|
* @param n the current textblock node.
|
|
|
|
* @param new_node the new node to set.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_evas_textblock_cursors_set_node(Evas_Object_Textblock *o,
|
|
|
|
const Evas_Object_Textblock_Node_Text *n,
|
|
|
|
Evas_Object_Textblock_Node_Text *new_node)
|
|
|
|
{
|
|
|
|
Eina_List *l;
|
|
|
|
Evas_Textblock_Cursor *data;
|
|
|
|
|
|
|
|
if (n == o->cursor->node)
|
|
|
|
{
|
|
|
|
o->cursor->pos = 0;
|
|
|
|
o->cursor->node = new_node;
|
|
|
|
}
|
|
|
|
EINA_LIST_FOREACH(o->cursors, l, data)
|
|
|
|
{
|
|
|
|
if (n == data->node)
|
|
|
|
{
|
|
|
|
data->pos = 0;
|
|
|
|
data->node = new_node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Update the offset of all the cursors after cur.
|
2010-08-11 03:27:44 -07:00
|
|
|
*
|
|
|
|
* @param cur the cursor.
|
|
|
|
* @param n the current textblock node.
|
|
|
|
* @param start the starting pos.
|
|
|
|
* @param offset how much to adjust (can be negative).
|
|
|
|
*/
|
|
|
|
static void
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur,
|
2010-08-11 03:27:44 -07:00
|
|
|
const Evas_Object_Textblock_Node_Text *n,
|
2010-08-18 06:56:34 -07:00
|
|
|
size_t start, int offset)
|
2010-08-11 03:27:44 -07:00
|
|
|
{
|
|
|
|
Eina_List *l;
|
|
|
|
Evas_Textblock_Cursor *data;
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
|
|
|
|
if (cur != o->cursor)
|
|
|
|
{
|
|
|
|
if ((n == o->cursor->node) &&
|
|
|
|
(o->cursor->pos > start))
|
|
|
|
{
|
2010-08-18 06:56:34 -07:00
|
|
|
if ((offset < 0) && (o->cursor->pos <= (size_t) (-1 * offset)))
|
|
|
|
{
|
|
|
|
o->cursor->pos = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
o->cursor->pos += offset;
|
|
|
|
}
|
2010-08-11 03:27:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
EINA_LIST_FOREACH(o->cursors, l, data)
|
|
|
|
{
|
|
|
|
if (data != cur)
|
|
|
|
{
|
|
|
|
if ((n == data->node) &&
|
|
|
|
(data->pos > start))
|
|
|
|
{
|
2010-08-18 06:56:34 -07:00
|
|
|
if ((offset < 0) && (data->pos <= (size_t) (-1 * offset)))
|
|
|
|
{
|
|
|
|
data->pos = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data->pos += offset;
|
|
|
|
}
|
2010-08-11 03:27:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:40:14 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
2011-04-07 04:24:11 -07:00
|
|
|
* Mark that the textblock has changed.
|
2011-01-30 02:40:14 -08:00
|
|
|
*
|
|
|
|
* @param o the textblock object.
|
|
|
|
* @param obj the evas object.
|
|
|
|
*/
|
|
|
|
static void
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj)
|
2011-01-30 02:40:14 -08:00
|
|
|
{
|
2011-01-30 02:40:36 -08:00
|
|
|
o->formatted.valid = 0;
|
|
|
|
o->native.valid = 0;
|
|
|
|
o->content_changed = 1;
|
|
|
|
if (o->markup_text)
|
|
|
|
{
|
|
|
|
free(o->markup_text);
|
|
|
|
o->markup_text = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
evas_object_change(obj);
|
2011-01-30 02:40:14 -08:00
|
|
|
}
|
|
|
|
|
2011-04-07 04:24:15 -07:00
|
|
|
static void
|
|
|
|
_evas_textblock_invalidate_all(Evas_Object_Textblock *o)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(o->text_nodes, n)
|
|
|
|
{
|
|
|
|
n->dirty = EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-22 03:58:44 -07:00
|
|
|
EAPI int
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2005-08-27 23:41:54 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
|
|
|
Evas_Object_Textblock_Node_Format *fnode = NULL;
|
2010-07-28 05:00:41 -07:00
|
|
|
Eina_Unicode *text;
|
2010-08-12 00:02:30 -07:00
|
|
|
int len = 0;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!cur) return 0;
|
2011-02-16 08:00:17 -08:00
|
|
|
text = eina_unicode_utf8_to_unicode(_text, &len);
|
2005-08-27 23:41:54 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
/* Update all the cursors after our position. */
|
2010-08-16 02:44:50 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, len);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-27 23:41:54 -07:00
|
|
|
n = cur->node;
|
2010-08-09 09:24:17 -07:00
|
|
|
if (n)
|
2010-03-11 06:29:25 -08:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *nnode;
|
2010-11-29 07:04:44 -08:00
|
|
|
fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
|
|
|
|
fnode = _evas_textblock_node_format_last_at_off(fnode);
|
2010-08-09 09:24:17 -07:00
|
|
|
/* 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)
|
2010-03-13 22:38:58 -08:00
|
|
|
{
|
2010-11-29 07:04:44 -08:00
|
|
|
if (!evas_textblock_cursor_format_is_visible_get(cur))
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-11-29 07:04:44 -08:00
|
|
|
nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
|
|
|
if (nnode && (nnode->text_node == n))
|
|
|
|
{
|
|
|
|
fnode = nnode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fnode = NULL;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-03-13 22:38:58 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
fnode = n->format_node;
|
2010-03-13 22:38:58 -08:00
|
|
|
}
|
2010-03-11 06:29:25 -08:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
else
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
n = _evas_textblock_node_text_new();
|
|
|
|
o->text_nodes = _NODE_TEXT(eina_inlist_append(
|
|
|
|
EINA_INLIST_GET(o->text_nodes),
|
|
|
|
EINA_INLIST_GET(n)));
|
|
|
|
cur->node = n;
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
eina_ustrbuf_insert_length(n->unicode, text, len, cur->pos);
|
|
|
|
/* Advance the formats */
|
|
|
|
if (fnode && (fnode->text_node == cur->node))
|
|
|
|
fnode->offset += len;
|
2011-04-14 05:13:20 -07:00
|
|
|
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, cur->obj);
|
|
|
|
n->dirty = EINA_TRUE;
|
2010-07-28 05:00:41 -07:00
|
|
|
free(text);
|
2010-08-09 09:24:17 -07:00
|
|
|
return len;
|
2005-08-14 08:48:07 -07:00
|
|
|
}
|
|
|
|
|
2010-09-22 03:58:44 -07:00
|
|
|
EAPI int
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text)
|
2005-08-11 06:50:37 -07:00
|
|
|
{
|
2010-09-22 03:58:44 -07:00
|
|
|
int len;
|
2010-08-09 09:24:17 -07:00
|
|
|
/*append is essentially prepend without advancing */
|
|
|
|
len = evas_textblock_cursor_text_append(cur, _text);
|
|
|
|
cur->pos += len; /*Advance */
|
2010-08-12 00:02:30 -07:00
|
|
|
return len;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Free a format node
|
|
|
|
*
|
|
|
|
* @prama n the format node to free
|
|
|
|
*/
|
2010-08-12 00:02:30 -07:00
|
|
|
static void
|
2010-08-09 09:24:17 -07:00
|
|
|
_evas_textblock_node_format_free(Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
if (!n) return;
|
|
|
|
eina_strbuf_free(n->format);
|
|
|
|
free(n);
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-10 07:36:48 -07:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Create a new format node.
|
|
|
|
*
|
|
|
|
* @param format the text to create the format node from.
|
|
|
|
* @return Returns the new format node
|
|
|
|
*/
|
2010-08-22 04:00:45 -07:00
|
|
|
static Evas_Object_Textblock_Node_Format *
|
2010-08-09 09:24:17 -07:00
|
|
|
_evas_textblock_node_format_new(const char *format)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Node_Format *n;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format));
|
|
|
|
n->format = eina_strbuf_new();
|
|
|
|
eina_strbuf_append(n->format, format);
|
|
|
|
n->visible = _evas_textblock_format_is_visible(format);
|
2011-04-27 05:41:26 -07:00
|
|
|
n->new = EINA_TRUE;
|
2005-08-20 01:01:59 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
return n;
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-22 04:00:45 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
const Eina_Unicode *text;
|
|
|
|
|
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
|
|
|
text = eina_ustrbuf_string_get(cur->node->unicode);
|
|
|
|
return ((text[cur->pos] == 0) && (!EINA_INLIST_GET(cur->node)->next)) ?
|
|
|
|
EINA_TRUE : EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
|
2005-08-27 23:41:54 -07:00
|
|
|
{
|
2005-08-28 06:56:37 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *n;
|
|
|
|
Eina_Bool is_visible;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if ((!format) || (format[0] == 0)) return EINA_FALSE;
|
2005-08-28 06:56:37 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
/* We should always have at least one text node */
|
|
|
|
if (!o->text_nodes)
|
2005-08-28 06:56:37 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_text_prepend(cur, "");
|
2005-08-28 06:56:37 -07:00
|
|
|
}
|
2010-03-15 17:56:11 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
n = _evas_textblock_node_format_new(format);
|
|
|
|
is_visible = n->visible;
|
|
|
|
if (!cur->node)
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_append(
|
|
|
|
EINA_INLIST_GET(o->format_nodes),
|
|
|
|
EINA_INLIST_GET(n)));
|
2005-09-09 07:19:06 -07:00
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
n->text_node = (EINA_INLIST_GET(n)->prev) ?
|
|
|
|
_NODE_FORMAT(EINA_INLIST_GET(n)->prev)->text_node :
|
|
|
|
o->text_nodes;
|
|
|
|
cur->node = n->text_node;
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *fmt;
|
|
|
|
fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
|
|
|
|
n->text_node = cur->node;
|
|
|
|
if (!fmt)
|
|
|
|
{
|
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_prepend(
|
|
|
|
EINA_INLIST_GET(o->format_nodes),
|
|
|
|
EINA_INLIST_GET(n)));
|
|
|
|
n->offset = cur->pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (evas_textblock_cursor_format_is_visible_get(cur))
|
|
|
|
{
|
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_prepend_relative(
|
|
|
|
EINA_INLIST_GET(o->format_nodes),
|
|
|
|
EINA_INLIST_GET(n),
|
|
|
|
EINA_INLIST_GET(fmt)
|
|
|
|
));
|
|
|
|
n->offset = fmt->offset;
|
|
|
|
if (fmt->text_node->format_node == fmt)
|
|
|
|
{
|
|
|
|
fmt->text_node->format_node = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fmt = _evas_textblock_node_format_last_at_off(fmt);
|
|
|
|
o->format_nodes = _NODE_FORMAT(eina_inlist_append_relative(
|
|
|
|
EINA_INLIST_GET(o->format_nodes),
|
|
|
|
EINA_INLIST_GET(n),
|
|
|
|
EINA_INLIST_GET(fmt)
|
|
|
|
));
|
|
|
|
if (fmt->text_node != cur->node)
|
|
|
|
{
|
|
|
|
n->offset = cur->pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
n->offset = cur->pos -
|
|
|
|
_evas_textblock_node_format_pos_get(fmt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Adjust differently if we insert a format char */
|
|
|
|
if (is_visible)
|
|
|
|
{
|
2010-08-26 02:22:31 -07:00
|
|
|
_evas_textblock_node_format_adjust_offset(o, cur->node, n,
|
|
|
|
-(n->offset - 1));
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-26 02:22:31 -07:00
|
|
|
_evas_textblock_node_format_adjust_offset(o, cur->node, n,
|
|
|
|
-n->offset);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2005-09-09 07:19:06 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!fmt || (fmt->text_node != cur->node))
|
|
|
|
{
|
|
|
|
cur->node->format_node = n;
|
|
|
|
}
|
|
|
|
}
|
2011-01-13 22:27:10 -08:00
|
|
|
if (is_visible && cur->node)
|
2005-09-10 04:51:52 -07:00
|
|
|
{
|
2011-05-05 06:38:04 -07:00
|
|
|
Eina_Unicode insert_char;
|
|
|
|
/* Insert a visual representation according to the type of the
|
|
|
|
format */
|
|
|
|
if (_IS_PARAGRAPH_SEPARATOR(o, format))
|
|
|
|
insert_char = _PARAGRAPH_SEPARATOR;
|
|
|
|
else if (_IS_LINE_SEPARATOR(format))
|
|
|
|
insert_char = '\n';
|
|
|
|
else if (_IS_TAB(format))
|
|
|
|
insert_char = '\t';
|
|
|
|
else
|
|
|
|
insert_char = EVAS_TEXTBLOCK_REPLACEMENT_CHAR;
|
|
|
|
|
|
|
|
eina_ustrbuf_insert_char(cur->node->unicode, insert_char, cur->pos);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
/* Advance all the cursors after our cursor */
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1);
|
2011-02-14 06:17:12 -08:00
|
|
|
if (_IS_PARAGRAPH_SEPARATOR(o, format))
|
2010-09-06 05:19:17 -07:00
|
|
|
{
|
|
|
|
_evas_textblock_cursor_break_paragraph(cur, n);
|
|
|
|
}
|
2011-04-27 05:41:26 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle visible format nodes here */
|
|
|
|
cur->node->dirty = EINA_TRUE;
|
|
|
|
n->new = EINA_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
o->format_changed = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, cur->obj);
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
return is_visible;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format)
|
|
|
|
{
|
|
|
|
Eina_Bool is_visible;
|
|
|
|
/* append is essentially prepend without advancing */
|
|
|
|
is_visible = evas_textblock_cursor_format_append(cur, format);
|
|
|
|
if (is_visible)
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
/* Advance after the replacement char */
|
|
|
|
evas_textblock_cursor_char_next(cur);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
return is_visible;
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n, *n2;
|
|
|
|
int merge_nodes = 0;
|
|
|
|
const Eina_Unicode *text;
|
2005-09-10 20:23:11 -07:00
|
|
|
int chr, index, ppos;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-29 01:27:13 -07:00
|
|
|
if (!cur || !cur->node) return;
|
2005-09-09 07:19:06 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
n = cur->node;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
text = eina_ustrbuf_string_get(n->unicode);
|
2005-09-09 07:19:06 -07:00
|
|
|
index = cur->pos;
|
2011-04-13 01:36:57 -07:00
|
|
|
if (text[index])
|
|
|
|
chr = text[index++];
|
2011-04-13 15:40:25 -07:00
|
|
|
else
|
|
|
|
chr = 0;
|
2011-04-13 01:36:57 -07:00
|
|
|
|
2005-09-09 07:19:06 -07:00
|
|
|
if (chr == 0) return;
|
2005-09-10 20:23:11 -07:00
|
|
|
ppos = cur->pos;
|
2010-08-09 09:24:17 -07:00
|
|
|
/* Remove a format node if needed, and remove the char only if the
|
|
|
|
* fmt node is not visible */
|
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *fmt, *fmt2;
|
2010-08-09 09:24:17 -07:00
|
|
|
fmt = _evas_textblock_cursor_node_format_at_pos_get(cur);
|
|
|
|
if (fmt)
|
|
|
|
{
|
|
|
|
const char *format = NULL;
|
2010-09-21 06:05:30 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *last_fmt;
|
2010-08-25 07:37:52 -07:00
|
|
|
/* If there's a PS it must be the last become it delimits paragraphs */
|
2010-09-21 06:05:30 -07:00
|
|
|
last_fmt = _evas_textblock_node_format_last_at_off(fmt);
|
|
|
|
format = eina_strbuf_string_get(last_fmt->format);
|
2011-02-14 06:17:12 -08:00
|
|
|
if (format && _IS_PARAGRAPH_SEPARATOR(o, format))
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
merge_nodes = 1;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-09-15 07:07:09 -07:00
|
|
|
/* If a singnular, mark as invisible, so we'll delete it. */
|
|
|
|
if (!format || ((*format != '+') && (*format != '-')))
|
|
|
|
{
|
2010-09-21 06:05:30 -07:00
|
|
|
last_fmt->visible = EINA_FALSE;
|
2010-09-15 07:07:09 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-25 07:37:52 -07:00
|
|
|
|
|
|
|
fmt2 = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
|
|
|
|
fmt2 = _evas_textblock_node_format_last_at_off(fmt2);
|
|
|
|
_evas_textblock_node_format_adjust_offset(o, cur->node, fmt2,
|
|
|
|
-(index - cur->pos));
|
|
|
|
|
|
|
|
_evas_textblock_node_format_remove_matching(o, fmt);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
eina_ustrbuf_remove(n->unicode, cur->pos, index);
|
|
|
|
/* If it was a paragraph separator, we should merge the current with the
|
|
|
|
* next, there must be a next. */
|
|
|
|
if (merge_nodes)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
_evas_textblock_cursor_nodes_merge(cur);
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
if (cur->pos == eina_ustrbuf_length_get(n->unicode))
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
n2 = _NODE_TEXT(EINA_INLIST_GET(n)->next);
|
2005-09-09 07:19:06 -07:00
|
|
|
if (n2)
|
|
|
|
{
|
|
|
|
cur->node = n2;
|
|
|
|
cur->pos = 0;
|
|
|
|
}
|
|
|
|
}
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur, n, ppos, -(index - ppos));
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, cur->obj);
|
|
|
|
cur->node->dirty = EINA_TRUE;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2011-04-07 04:24:15 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n1, *n2;
|
2010-11-07 23:46:43 -08:00
|
|
|
Eina_Bool should_merge = EINA_FALSE, reset_cursor = EINA_FALSE;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
if (!cur1 || !cur1->node) return;
|
|
|
|
if (!cur2 || !cur2->node) return;
|
|
|
|
if (cur1->obj != cur2->obj) return;
|
|
|
|
o = (Evas_Object_Textblock *)(cur1->obj->object_data);
|
|
|
|
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
|
|
|
|
{
|
|
|
|
Evas_Textblock_Cursor *tc;
|
|
|
|
|
|
|
|
tc = cur1;
|
|
|
|
cur1 = cur2;
|
|
|
|
cur2 = tc;
|
|
|
|
}
|
|
|
|
n1 = cur1->node;
|
|
|
|
n2 = cur2->node;
|
2010-11-07 23:46:43 -08:00
|
|
|
if ((evas_textblock_cursor_compare(o->cursor, cur1) >= 0) &&
|
|
|
|
(evas_textblock_cursor_compare(cur2, o->cursor) >= 0))
|
|
|
|
{
|
|
|
|
reset_cursor = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
if (n1 == n2)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-26 02:22:31 -07:00
|
|
|
if ((cur1->pos == 0) &&
|
|
|
|
(cur2->pos == eina_ustrbuf_length_get(n1->unicode)))
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_node_text_remove_formats_between(o, n1, 0, -1);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-26 02:22:31 -07:00
|
|
|
should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o,
|
|
|
|
n1, cur1->pos, cur2->pos);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-10-05 09:17:01 -07:00
|
|
|
eina_ustrbuf_remove(n1->unicode, cur1->pos, cur2->pos);
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos, - (cur2->pos - cur1->pos));
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-07 04:24:15 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n;
|
2010-08-09 09:24:17 -07:00
|
|
|
int len;
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_node_text_adjust_offsets_to_start(o, n1, cur1->pos, -1);
|
2010-08-09 09:24:17 -07:00
|
|
|
n = _NODE_TEXT(EINA_INLIST_GET(n1)->next);
|
|
|
|
/* Remove all the text nodes between */
|
|
|
|
while (n && (n != n2))
|
|
|
|
{
|
2010-08-18 06:56:34 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *nnode;
|
|
|
|
|
|
|
|
nnode = _NODE_TEXT(EINA_INLIST_GET(n)->next);
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_cursors_set_node(o, n, n1);
|
2010-08-09 09:24:17 -07:00
|
|
|
_evas_textblock_node_text_remove(o, n);
|
2010-08-18 06:56:34 -07:00
|
|
|
n = nnode;
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2010-08-26 02:22:31 -07:00
|
|
|
should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o, n2,
|
|
|
|
0, cur2->pos);
|
2010-08-09 09:24:17 -07:00
|
|
|
|
|
|
|
/* Remove the formats and the strings in the first and last nodes */
|
|
|
|
len = eina_ustrbuf_length_get(n1->unicode);
|
|
|
|
eina_ustrbuf_remove(n1->unicode, cur1->pos, len);
|
|
|
|
eina_ustrbuf_remove(n2->unicode, 0, cur2->pos);
|
|
|
|
/* Merge the nodes because we removed the PS */
|
2010-08-26 02:22:31 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos,
|
|
|
|
- cur1->pos);
|
2010-08-12 07:59:42 -07:00
|
|
|
_evas_textblock_cursors_update_offset(cur2, cur2->node, 0, - cur2->pos);
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_nodes_merge(o, n1);
|
|
|
|
}
|
|
|
|
_evas_textblock_node_format_remove_matching(o,
|
|
|
|
_evas_textblock_cursor_node_format_at_pos_get(cur1));
|
|
|
|
|
|
|
|
if (should_merge)
|
|
|
|
{
|
2010-09-01 01:25:19 -07:00
|
|
|
/* We call this function instead of the cursor one because we already
|
|
|
|
* updated the cursors */
|
2010-08-25 07:37:52 -07:00
|
|
|
_evas_textblock_nodes_merge(o, n1);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-09-01 01:25:19 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_copy(cur1, cur2);
|
2010-11-07 23:46:43 -08:00
|
|
|
if (reset_cursor)
|
|
|
|
evas_textblock_cursor_copy(cur1, o->cursor);
|
|
|
|
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, cur1->obj);
|
2011-04-07 04:24:15 -07:00
|
|
|
n1->dirty = n2->dirty = EINA_TRUE;
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
|
2010-09-05 01:28:58 -07:00
|
|
|
|
|
|
|
EAPI char *
|
|
|
|
evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
const Eina_Unicode *ustr;
|
|
|
|
Eina_Unicode buf[2];
|
|
|
|
char *s;
|
|
|
|
if (!cur || !cur->node) return NULL;
|
|
|
|
if (evas_textblock_cursor_format_is_visible_get(cur))
|
|
|
|
{
|
2010-10-06 11:26:29 -07:00
|
|
|
const char *tmp;
|
|
|
|
tmp = evas_textblock_node_format_text_get(
|
|
|
|
_evas_textblock_node_visible_at_pos_get(
|
|
|
|
evas_textblock_cursor_format_get(cur)));
|
|
|
|
return strdup(tmp);
|
2010-09-05 01:28:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ustr = eina_ustrbuf_string_get(cur->node->unicode);
|
|
|
|
buf[0] = ustr[cur->pos];
|
|
|
|
buf[1] = 0;
|
2011-02-16 08:00:17 -08:00
|
|
|
s = eina_unicode_unicode_to_utf8(buf, NULL);
|
2010-09-05 01:28:58 -07:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI char *
|
2010-08-11 05:29:20 -07:00
|
|
|
evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2, Evas_Textblock_Text_Type format __UNUSED__)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2010-08-11 05:29:20 -07:00
|
|
|
Evas_Object_Textblock_Node_Text *n1, *n2, *tnode;
|
|
|
|
Eina_Strbuf *buf;
|
2010-08-09 09:24:17 -07:00
|
|
|
Evas_Textblock_Cursor *cur2;
|
2010-08-11 05:29:20 -07:00
|
|
|
buf = eina_strbuf_new();
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2010-08-12 00:02:30 -07:00
|
|
|
if (!cur1 || !cur1->node) return NULL;
|
|
|
|
if (!_cur2 || !_cur2->node) return NULL;
|
|
|
|
if (cur1->obj != _cur2->obj) return NULL;
|
2005-09-09 07:19:06 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur1->obj->object_data);
|
2010-08-09 09:24:17 -07:00
|
|
|
if (evas_textblock_cursor_compare(cur1, _cur2) > 0)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
const Evas_Textblock_Cursor *tc;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-09-09 07:19:06 -07:00
|
|
|
tc = cur1;
|
2010-08-09 09:24:17 -07:00
|
|
|
cur1 = _cur2;
|
|
|
|
_cur2 = tc;
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
n1 = cur1->node;
|
2010-08-09 09:24:17 -07:00
|
|
|
n2 = _cur2->node;
|
|
|
|
/* Work on a local copy of the cur */
|
|
|
|
cur2 = alloca(sizeof(Evas_Textblock_Cursor));
|
|
|
|
cur2->obj = _cur2->obj;
|
|
|
|
evas_textblock_cursor_copy(_cur2, cur2);
|
2010-10-05 03:50:58 -07:00
|
|
|
|
2010-08-11 05:29:20 -07:00
|
|
|
/* Parse the text between the cursors. */
|
|
|
|
for (tnode = cur1->node ; tnode ;
|
|
|
|
tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next))
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2010-08-11 05:29:20 -07:00
|
|
|
Evas_Object_Textblock_Node_Format *fnode;
|
|
|
|
Eina_Unicode *text_base, *text;
|
2010-09-18 18:33:51 -07:00
|
|
|
int off = 0;
|
2010-08-11 05:29:20 -07:00
|
|
|
|
|
|
|
text_base = text =
|
2011-02-14 02:49:09 -08:00
|
|
|
eina_unicode_strndup(eina_ustrbuf_string_get(tnode->unicode),
|
|
|
|
eina_ustrbuf_length_get(tnode->unicode));
|
2010-08-16 01:52:18 -07:00
|
|
|
if (tnode == cur2->node)
|
|
|
|
{
|
2010-08-19 07:07:45 -07:00
|
|
|
fnode = _evas_textblock_node_text_get_first_format_between(tnode,
|
2010-08-16 01:52:18 -07:00
|
|
|
cur1->pos, cur2->pos);
|
|
|
|
}
|
2010-08-19 07:07:45 -07:00
|
|
|
else if (tnode == cur1->node)
|
2010-08-16 01:52:18 -07:00
|
|
|
{
|
2010-08-19 07:07:45 -07:00
|
|
|
fnode = _evas_textblock_node_text_get_first_format_between(tnode,
|
2010-08-16 01:52:18 -07:00
|
|
|
cur1->pos, -1);
|
|
|
|
}
|
2010-08-19 07:07:45 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fnode = _evas_textblock_node_text_get_first_format_between(tnode,
|
|
|
|
0, -1);
|
|
|
|
}
|
2010-08-11 05:29:20 -07:00
|
|
|
/* Init the offset so the first one will count starting from cur1->pos
|
|
|
|
* and not the previous format node */
|
2010-09-16 00:12:23 -07:00
|
|
|
if (tnode == cur1->node)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2010-09-16 00:12:23 -07:00
|
|
|
if (fnode)
|
|
|
|
{
|
|
|
|
off = _evas_textblock_node_format_pos_get(fnode) -
|
|
|
|
cur1->pos - fnode->offset;
|
|
|
|
}
|
2010-08-19 07:07:45 -07:00
|
|
|
text += cur1->pos;
|
2010-08-11 05:29:20 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
off = 0;
|
|
|
|
}
|
|
|
|
while (fnode && (fnode->text_node == tnode))
|
|
|
|
{
|
|
|
|
Eina_Unicode tmp_ch;
|
|
|
|
off += fnode->offset;
|
2010-08-26 02:22:31 -07:00
|
|
|
if ((tnode == cur2->node) &&
|
|
|
|
((size_t) (text - text_base + off) >= cur2->pos))
|
2010-08-11 05:29:20 -07:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* No need to skip on the first run */
|
|
|
|
tmp_ch = text[off];
|
|
|
|
text[off] = 0; /* Null terminate the part of the string */
|
|
|
|
_markup_get_text_append(buf, text);
|
|
|
|
_markup_get_format_append(o, buf, fnode);
|
|
|
|
text[off] = tmp_ch; /* Restore the char */
|
|
|
|
text += off;
|
|
|
|
if (fnode->visible)
|
|
|
|
{
|
|
|
|
off = -1;
|
|
|
|
text++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
off = 0;
|
|
|
|
}
|
|
|
|
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
|
|
|
|
}
|
|
|
|
/* If we got to the last node, stop and add the rest outside */
|
|
|
|
if (cur2->node == tnode)
|
|
|
|
{
|
|
|
|
/* Add the rest, skip replacement */
|
|
|
|
/* Don't go past the second cursor pos */
|
|
|
|
text_base[cur2->pos] = '\0';
|
|
|
|
_markup_get_text_append(buf, text);
|
|
|
|
free(text_base);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add the rest, skip replacement */
|
|
|
|
_markup_get_text_append(buf, text);
|
|
|
|
free(text_base);
|
2010-08-09 09:24:17 -07:00
|
|
|
}
|
2005-09-10 20:23:11 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
/* return the string */
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
char *ret;
|
2010-08-11 05:29:20 -07:00
|
|
|
ret = eina_strbuf_string_steal(buf);
|
|
|
|
eina_strbuf_free(buf);
|
2010-08-09 09:24:17 -07:00
|
|
|
return ret;
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2005-08-27 23:41:54 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI const char *
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur)
|
2005-08-27 23:41:54 -07:00
|
|
|
{
|
2010-08-16 02:40:01 -07:00
|
|
|
Evas_Textblock_Cursor cur1, cur2;
|
2005-08-27 23:41:54 -07:00
|
|
|
if (!cur) return NULL;
|
|
|
|
if (!cur->node) return NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
if (cur->node->utf8)
|
2005-08-27 23:41:54 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
free(cur->node->utf8);
|
2005-08-27 23:41:54 -07:00
|
|
|
}
|
2010-08-16 02:40:01 -07:00
|
|
|
cur1.obj = cur2.obj = cur->obj;
|
|
|
|
cur1.node = cur2.node = cur->node;
|
|
|
|
evas_textblock_cursor_paragraph_char_first(&cur1);
|
|
|
|
evas_textblock_cursor_paragraph_char_last(&cur2);
|
|
|
|
|
|
|
|
cur->node->utf8 = evas_textblock_cursor_range_text_get(&cur1, &cur2,
|
|
|
|
EVAS_TEXTBLOCK_TEXT_MARKUP);
|
2010-08-09 09:24:17 -07:00
|
|
|
return cur->node->utf8;
|
2005-08-27 23:41:54 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI int
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur)
|
2005-09-10 04:51:52 -07:00
|
|
|
{
|
2010-08-10 07:36:48 -07:00
|
|
|
if (!cur) return -1;
|
|
|
|
if (!cur->node) return -1;
|
2010-08-09 09:24:17 -07:00
|
|
|
return eina_ustrbuf_length_get(cur->node->unicode);
|
2005-09-10 04:51:52 -07:00
|
|
|
}
|
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI const Evas_Object_Textblock_Node_Format *
|
|
|
|
evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
if (!cur) return NULL;
|
|
|
|
if (!cur->node) return NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
return _evas_textblock_cursor_node_format_at_pos_get(cur);
|
2005-08-11 06:50:37 -07:00
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI const char *
|
|
|
|
evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt)
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!fmt) return NULL;
|
|
|
|
return eina_strbuf_string_get(fmt->format);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI void
|
|
|
|
evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!fmt || !cur) return;
|
|
|
|
cur->node = fmt->text_node;
|
|
|
|
cur->pos = _evas_textblock_node_format_pos_get(fmt);
|
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
|
|
|
const Eina_Unicode *text;
|
2009-06-14 13:48:37 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
|
|
|
if (!cur->node) return EINA_FALSE;
|
|
|
|
text = eina_ustrbuf_string_get(cur->node->unicode);
|
2011-05-05 06:38:04 -07:00
|
|
|
return EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(text[cur->pos]);
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
|
2010-09-02 04:49:00 -07:00
|
|
|
EAPI int
|
2010-09-08 00:28:16 -07:00
|
|
|
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)
|
2010-09-02 04:49:00 -07:00
|
|
|
{
|
2010-09-08 00:28:16 -07:00
|
|
|
int ret = -1;
|
2010-09-16 02:59:39 -07:00
|
|
|
const Evas_Textblock_Cursor *dir_cur;
|
2011-01-30 02:44:55 -08:00
|
|
|
Evas_Textblock_Cursor cur2;
|
2011-04-14 00:34:06 -07:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2010-09-16 02:59:39 -07:00
|
|
|
|
|
|
|
dir_cur = cur;
|
2010-09-02 04:49:00 -07:00
|
|
|
if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER)
|
|
|
|
{
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch);
|
2010-09-02 04:49:00 -07:00
|
|
|
}
|
|
|
|
else if (ctype == EVAS_TEXTBLOCK_CURSOR_BEFORE)
|
|
|
|
{
|
|
|
|
/* In the case of a "before cursor", we should get the coordinates
|
|
|
|
* of just after the previous char (which in bidi text may not be
|
|
|
|
* just before the current char). */
|
|
|
|
Evas_Coord x, y, h, w;
|
2011-01-30 02:32:09 -08:00
|
|
|
Evas_Object_Textblock_Node_Format *fmt;
|
|
|
|
|
2010-09-16 02:59:39 -07:00
|
|
|
/* If it's at the end of the line, we want to get the position, not
|
|
|
|
* the position of the previous */
|
|
|
|
if ((cur->pos > 0) && !_evas_textblock_cursor_is_at_the_end(cur))
|
2010-09-02 04:49:00 -07:00
|
|
|
{
|
2011-01-30 02:32:09 -08:00
|
|
|
Eina_Bool before_char = EINA_FALSE;
|
2011-01-30 02:44:55 -08:00
|
|
|
cur2.obj = cur->obj;
|
|
|
|
evas_textblock_cursor_copy(cur, &cur2);
|
|
|
|
evas_textblock_cursor_char_prev(&cur2);
|
|
|
|
|
|
|
|
fmt = _evas_textblock_cursor_node_format_at_pos_get(&cur2);
|
|
|
|
|
2011-01-30 02:32:09 -08:00
|
|
|
if (!fmt ||
|
|
|
|
!_IS_LINE_SEPARATOR(eina_strbuf_string_get(fmt->format)))
|
|
|
|
{
|
|
|
|
dir_cur = &cur2;
|
|
|
|
before_char = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
before_char = EINA_TRUE;
|
|
|
|
}
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = evas_textblock_cursor_pen_geometry_get(
|
2011-01-30 02:32:09 -08:00
|
|
|
dir_cur, &x, &y, &w, &h);
|
2010-09-16 02:59:39 -07:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
/* Adjust if the char is an rtl char */
|
|
|
|
if (ret >= 0)
|
|
|
|
{
|
2011-01-30 02:32:09 -08:00
|
|
|
if ((!before_char &&
|
2011-04-14 05:13:20 -07:00
|
|
|
evas_bidi_is_rtl_char(
|
|
|
|
dir_cur->node->par->bidi_props, 0,
|
2011-01-30 02:35:04 -08:00
|
|
|
dir_cur->pos)) ||
|
2011-01-30 02:32:09 -08:00
|
|
|
(before_char &&
|
2011-04-14 05:13:20 -07:00
|
|
|
!evas_bidi_is_rtl_char(
|
|
|
|
dir_cur->node->par->bidi_props, 0,
|
2011-01-30 02:35:04 -08:00
|
|
|
dir_cur->pos)))
|
2011-01-30 02:32:09 -08:00
|
|
|
|
2010-09-16 02:59:39 -07:00
|
|
|
{
|
|
|
|
/* Just don't advance the width */
|
|
|
|
w = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:44:55 -08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (cur->pos == 0)
|
|
|
|
{
|
|
|
|
ret = evas_textblock_cursor_pen_geometry_get(
|
|
|
|
dir_cur, &x, &y, &w, &h);
|
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
/* Adjust if the char is an rtl char */
|
|
|
|
if ((ret >= 0) && (!evas_bidi_is_rtl_char(
|
2011-04-14 05:13:20 -07:00
|
|
|
dir_cur->node->par->bidi_props, 0, dir_cur->pos)))
|
2011-01-30 02:44:55 -08:00
|
|
|
{
|
|
|
|
/* Just don't advance the width */
|
|
|
|
w = 0;
|
|
|
|
}
|
2010-09-16 02:59:39 -07:00
|
|
|
#endif
|
2010-09-02 04:49:00 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = evas_textblock_cursor_pen_geometry_get(
|
2011-01-30 02:32:09 -08:00
|
|
|
dir_cur, &x, &y, &w, &h);
|
2010-09-02 04:49:00 -07:00
|
|
|
}
|
2010-09-16 02:59:39 -07:00
|
|
|
if (ret >= 0)
|
2010-09-02 04:49:00 -07:00
|
|
|
{
|
|
|
|
if (cx) *cx = x + w;
|
2010-09-16 02:59:39 -07:00
|
|
|
if (cy) *cy = y;
|
2010-09-02 04:49:00 -07:00
|
|
|
if (cw) *cw = 0;
|
2010-09-16 02:59:39 -07:00
|
|
|
if (ch) *ch = h;
|
2010-09-02 04:49:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-16 02:59:39 -07:00
|
|
|
if (dir && dir_cur && dir_cur->node)
|
2010-09-08 00:28:16 -07:00
|
|
|
{
|
|
|
|
#ifdef BIDI_SUPPORT
|
2011-01-30 02:35:50 -08:00
|
|
|
if (_evas_textblock_cursor_is_at_the_end(dir_cur) && (dir_cur->pos > 0))
|
|
|
|
{
|
2011-04-14 05:13:20 -07:00
|
|
|
*dir = (evas_bidi_is_rtl_char(dir_cur->node->par->bidi_props, 0,
|
2011-01-30 02:35:50 -08:00
|
|
|
dir_cur->pos - 1)) ?
|
|
|
|
EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
|
|
|
|
}
|
|
|
|
else if (dir_cur->pos > 0)
|
|
|
|
{
|
2011-04-14 05:13:20 -07:00
|
|
|
*dir = (evas_bidi_is_rtl_char(dir_cur->node->par->bidi_props, 0,
|
2011-01-30 02:35:50 -08:00
|
|
|
dir_cur->pos)) ?
|
|
|
|
EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
|
|
|
|
}
|
|
|
|
else
|
2010-09-08 00:28:16 -07:00
|
|
|
#endif
|
2011-01-30 02:35:50 -08:00
|
|
|
{
|
|
|
|
*dir = EVAS_BIDI_DIRECTION_LTR;
|
|
|
|
}
|
2010-09-08 00:28:16 -07:00
|
|
|
}
|
|
|
|
return ret;
|
2010-09-02 04:49:00 -07:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:34:29 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns the geometry/pen position (depending on query_func) of the char
|
|
|
|
* at pos.
|
|
|
|
*
|
|
|
|
* @param cur the position of the char.
|
|
|
|
* @param query_func the query function to use.
|
|
|
|
* @param cx the x of the char (or pen_x in the case of pen position).
|
|
|
|
* @param cy the y of the char.
|
|
|
|
* @param cw the w of the char (or advance in the case pen position).
|
|
|
|
* @param ch the h of the char.
|
|
|
|
* @return line number of the char on success, -1 on error.
|
2008-06-28 03:55:58 -07:00
|
|
|
*/
|
2011-01-30 02:34:13 -08:00
|
|
|
static int
|
2011-04-07 09:25:56 -07:00
|
|
|
_evas_textblock_cursor_char_pen_geometry_common_get(int (*query_func) (void *data, void *font, const Evas_Text_Props *intl_props, int pos, int *cx, int *cy, int *cw, int *ch), const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln = NULL;
|
2011-01-30 02:31:22 -08:00
|
|
|
Evas_Object_Textblock_Item *it = NULL;
|
2011-01-30 02:31:16 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti = NULL;
|
2005-08-20 22:13:49 -07:00
|
|
|
Evas_Object_Textblock_Format_Item *fi = NULL;
|
|
|
|
int x = 0, y = 0, w = 0, h = 0;
|
2005-08-20 01:01:59 -07:00
|
|
|
int pos, ret;
|
2011-01-30 02:31:22 -08:00
|
|
|
Eina_Bool previous_format;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 22:13:49 -07:00
|
|
|
if (!cur) return -1;
|
2010-03-12 03:15:19 -08:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2011-04-14 00:34:06 -07:00
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
|
|
|
|
2008-10-15 02:58:17 -07:00
|
|
|
if (!cur->node)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
if (!o->text_nodes)
|
2010-03-12 03:15:19 -08:00
|
|
|
{
|
2010-08-15 02:10:15 -07:00
|
|
|
if (!o->paragraphs) return -1;
|
|
|
|
ln = o->paragraphs->lines;
|
2010-03-12 03:15:19 -08:00
|
|
|
if (!ln) return -1;
|
2011-01-30 02:40:09 -08:00
|
|
|
if (cx) *cx = ln->par->x + ln->x;
|
|
|
|
if (cy) *cy = ln->par->y + ln->y;
|
2010-03-12 03:15:19 -08:00
|
|
|
if (cw) *cw = ln->w;
|
|
|
|
if (ch) *ch = ln->h;
|
2011-01-30 02:39:47 -08:00
|
|
|
return ln->par->line_no + ln->line_no;
|
2010-03-12 03:15:19 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return -1;
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-08-22 04:00:45 -07:00
|
|
|
|
2011-01-30 02:31:22 -08:00
|
|
|
previous_format = _find_layout_item_match(cur, &ln, &it);
|
2011-01-30 02:31:45 -08:00
|
|
|
if (!it)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2011-01-30 02:31:22 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
2010-08-22 04:00:45 -07:00
|
|
|
{
|
2011-01-30 02:31:22 -08:00
|
|
|
ti = _ITEM_TEXT(it);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2010-08-22 04:00:45 -07:00
|
|
|
else
|
2008-10-15 02:58:17 -07:00
|
|
|
{
|
2011-01-30 02:31:22 -08:00
|
|
|
fi = _ITEM_FORMAT(it);
|
2008-10-15 02:58:17 -07:00
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:31:16 -08:00
|
|
|
if (ln && ti)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2011-01-30 02:31:16 -08:00
|
|
|
pos = cur->pos - ti->parent.text_pos;
|
2010-08-09 09:24:17 -07:00
|
|
|
ret = -1;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2009-05-14 05:52:44 -07:00
|
|
|
if (pos < 0) pos = 0;
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->font.font)
|
2010-08-09 09:24:17 -07:00
|
|
|
{
|
2011-01-30 02:34:13 -08:00
|
|
|
ret = query_func(cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2010-08-09 09:24:17 -07:00
|
|
|
pos,
|
|
|
|
&x, &y, &w, &h);
|
|
|
|
}
|
2011-01-30 02:31:08 -08:00
|
|
|
|
2011-01-30 02:40:09 -08:00
|
|
|
x += ln->par->x + ln->x + _ITEM(ti)->x;
|
2011-01-30 02:32:45 -08:00
|
|
|
|
2011-01-30 02:40:09 -08:00
|
|
|
if (x < ln->par->x + ln->x)
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x;
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
2011-01-30 02:40:09 -08:00
|
|
|
y = ln->par->y + ln->y;
|
2005-08-20 22:13:49 -07:00
|
|
|
h = ln->h;
|
|
|
|
}
|
2010-08-22 04:00:45 -07:00
|
|
|
else if (ln && fi)
|
2005-08-20 22:13:49 -07:00
|
|
|
{
|
2010-08-22 04:00:45 -07:00
|
|
|
if (previous_format)
|
|
|
|
{
|
|
|
|
if (_IS_LINE_SEPARATOR(
|
|
|
|
eina_strbuf_string_get(fi->source_node->format)))
|
|
|
|
{
|
|
|
|
x = 0;
|
2011-01-30 02:40:09 -08:00
|
|
|
y = ln->par->y + ln->y + ln->h;
|
2010-08-22 04:00:45 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:31:08 -08:00
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
if (EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(
|
2011-04-14 05:13:20 -07:00
|
|
|
ln->par->bidi_props))
|
2011-01-30 02:31:08 -08:00
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x;
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x + ln->w;
|
2011-01-30 02:31:08 -08:00
|
|
|
}
|
2011-01-30 02:40:09 -08:00
|
|
|
y = ln->par->y + ln->y;
|
2010-08-22 04:00:45 -07:00
|
|
|
}
|
|
|
|
w = 0;
|
|
|
|
h = ln->h;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x + _ITEM(fi)->x;
|
|
|
|
y = ln->par->y + ln->y;
|
2011-01-30 02:31:16 -08:00
|
|
|
w = _ITEM(fi)->w;
|
2010-08-22 04:00:45 -07:00
|
|
|
h = ln->h;
|
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
}
|
2008-10-15 02:58:17 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2005-08-20 01:01:59 -07:00
|
|
|
if (cx) *cx = x;
|
|
|
|
if (cy) *cy = y;
|
|
|
|
if (cw) *cw = w;
|
|
|
|
if (ch) *ch = h;
|
2011-01-30 02:39:47 -08:00
|
|
|
return ln->par->line_no + ln->line_no;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2011-01-30 02:34:13 -08:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
return _evas_textblock_cursor_char_pen_geometry_common_get(
|
|
|
|
cur->ENFN->font_char_coords_get, cur, cx, cy, cw, ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_textblock_cursor_pen_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
|
|
|
|
{
|
|
|
|
return _evas_textblock_cursor_char_pen_geometry_common_get(
|
|
|
|
cur->ENFN->font_pen_coords_get, cur, cx, cy, cw, ch);
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI int
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln = NULL;
|
2011-01-30 02:31:22 -08:00
|
|
|
Evas_Object_Textblock_Item *it = NULL;
|
2005-08-20 01:01:59 -07:00
|
|
|
int x, y, w, h;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
if (!cur) return -1;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
2005-08-30 08:19:39 -07:00
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2010-03-14 05:24:42 -07:00
|
|
|
if (!cur->node)
|
|
|
|
{
|
2010-08-15 02:10:15 -07:00
|
|
|
ln = o->paragraphs->lines;
|
2010-03-14 05:24:42 -07:00
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
else
|
2010-03-14 05:24:42 -07:00
|
|
|
{
|
2011-01-30 02:31:22 -08:00
|
|
|
_find_layout_item_match(cur, &ln, &it);
|
2010-03-14 05:24:42 -07:00
|
|
|
}
|
2005-08-20 22:13:49 -07:00
|
|
|
if (!ln) return -1;
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x;
|
|
|
|
y = ln->par->y + ln->y;
|
2005-08-20 01:01:59 -07:00
|
|
|
w = ln->w;
|
|
|
|
h = ln->h;
|
|
|
|
if (cx) *cx = x;
|
|
|
|
if (cy) *cy = y;
|
|
|
|
if (cw) *cw = w;
|
|
|
|
if (ch) *ch = h;
|
2011-01-30 02:39:47 -08:00
|
|
|
return ln->par->line_no + ln->line_no;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
|
2005-09-02 08:27:09 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2011-01-30 02:40:04 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
2005-09-04 04:34:03 -07:00
|
|
|
Evas_Object_Textblock_Item *it = NULL, *it_break = NULL;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
2005-09-02 08:27:09 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2005-09-09 07:19:06 -07:00
|
|
|
x += o->style_pad.l;
|
|
|
|
y += o->style_pad.t;
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par)
|
2005-09-02 08:27:09 -07:00
|
|
|
{
|
2011-01-30 02:40:04 -08:00
|
|
|
if ((par->x <= x) && (par->x + par->w > x) &&
|
|
|
|
(par->y <= y) && (par->y + par->h > y))
|
|
|
|
{
|
|
|
|
found_par = par;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found_par)
|
|
|
|
{
|
|
|
|
EINA_INLIST_FOREACH(found_par->lines, ln)
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
if (ln->par->y + ln->y > y) break;
|
|
|
|
if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y))
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
|
|
|
EINA_INLIST_FOREACH(ln->items, it)
|
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
if ((it->x + ln->par->x + ln->x) > x)
|
2011-01-30 02:31:16 -08:00
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
it_break = it;
|
|
|
|
break;
|
2011-01-30 02:31:16 -08:00
|
|
|
}
|
2011-01-30 02:40:09 -08:00
|
|
|
if (((it->x + ln->par->x + ln->x) <= x) && (((it->x + ln->par->x + ln->x) + it->adv) > x))
|
2011-01-30 02:31:16 -08:00
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
int cx, cy, cw, ch;
|
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
|
|
|
ti = _ITEM_TEXT(it);
|
|
|
|
|
|
|
|
pos = -1;
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->font.font)
|
2011-01-30 02:39:47 -08:00
|
|
|
pos = cur->ENFN->font_char_at_coords_get(
|
|
|
|
cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2011-01-30 02:40:09 -08:00
|
|
|
x - it->x - ln->par->x - ln->x, 0,
|
2011-01-30 02:39:47 -08:00
|
|
|
&cx, &cy, &cw, &ch);
|
|
|
|
if (pos < 0)
|
|
|
|
return EINA_FALSE;
|
|
|
|
cur->pos = pos + it->text_pos;
|
|
|
|
cur->node = it->text_node;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
fi = _ITEM_FORMAT(it);
|
|
|
|
cur->pos = fi->parent.text_pos;
|
|
|
|
cur->node = fi->source_node->text_node;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2011-01-30 02:31:16 -08:00
|
|
|
}
|
2010-09-02 06:53:14 -07:00
|
|
|
}
|
2011-01-30 02:39:47 -08:00
|
|
|
if (it_break)
|
|
|
|
{
|
|
|
|
it = it_break;
|
|
|
|
cur->node = it->text_node;
|
|
|
|
cur->pos = it->text_pos;
|
|
|
|
|
|
|
|
/*FIXME: needs smarter handling, ATM just check, if it's
|
|
|
|
* the first item, then go to the end of the line, helps
|
|
|
|
* with rtl langs, doesn't affect ltr langs that much. */
|
|
|
|
if (!EINA_INLIST_GET(it)->prev)
|
|
|
|
{
|
|
|
|
evas_textblock_cursor_line_char_last(cur);
|
|
|
|
}
|
2010-09-02 06:53:14 -07:00
|
|
|
|
2011-01-30 02:39:47 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-09-02 08:27:09 -07:00
|
|
|
}
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_FALSE;
|
2005-09-02 08:27:09 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI int
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2011-01-30 02:40:04 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
|
|
|
|
2005-09-09 07:19:06 -07:00
|
|
|
if (!cur) return -1;
|
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
|
|
|
y += o->style_pad.t;
|
2011-01-30 02:40:04 -08:00
|
|
|
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2011-01-30 02:40:04 -08:00
|
|
|
if ((par->y <= y) && (par->y + par->h > y))
|
|
|
|
{
|
|
|
|
found_par = par;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found_par)
|
|
|
|
{
|
|
|
|
EINA_INLIST_FOREACH(found_par->lines, ln)
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
2011-01-30 02:40:09 -08:00
|
|
|
if (ln->par->y + ln->y > y) break;
|
|
|
|
if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y))
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
|
|
|
evas_textblock_cursor_line_set(cur, ln->par->line_no +
|
|
|
|
ln->line_no);
|
|
|
|
return ln->par->line_no + ln->line_no;
|
|
|
|
}
|
|
|
|
}
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:32:33 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Updates x and w according to the text direction, position in text and
|
|
|
|
* if it's a special case switch
|
|
|
|
*
|
|
|
|
* @param ti the text item we are working on
|
|
|
|
* @param x the current x (we get) and the x we return
|
|
|
|
* @param w the current w (we get) and the w we return
|
|
|
|
* @param start if this is the first item or not
|
|
|
|
* @param switch_items toogles item switching (rtl cases)
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-30 02:33:06 -08:00
|
|
|
_evas_textblock_range_calc_x_w(const Evas_Object_Textblock_Item *it,
|
2011-01-30 02:32:33 -08:00
|
|
|
Evas_Coord *x, Evas_Coord *w, Eina_Bool start, Eina_Bool switch_items)
|
|
|
|
{
|
|
|
|
if ((start && !switch_items) || (!start && switch_items))
|
|
|
|
{
|
|
|
|
#ifdef BIDI_SUPPORT
|
2011-02-14 05:09:41 -08:00
|
|
|
if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
|
|
|
|
_ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
|
|
|
|
||
|
|
|
|
((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
|
|
|
|
_ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL))
|
2011-01-30 02:32:33 -08:00
|
|
|
{
|
|
|
|
*w = *x + *w;
|
|
|
|
*x = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2011-01-30 02:33:19 -08:00
|
|
|
*w = it->adv - *x;
|
2011-01-30 02:32:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef BIDI_SUPPORT
|
2011-02-14 05:09:41 -08:00
|
|
|
if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
|
|
|
|
_ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
|
|
|
|
||
|
|
|
|
((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
|
|
|
|
_ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL))
|
2011-01-30 02:32:33 -08:00
|
|
|
{
|
|
|
|
*x = *x + *w;
|
2011-01-30 02:33:19 -08:00
|
|
|
*w = it->adv - *x;
|
2011-01-30 02:32:33 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
*w = *x;
|
|
|
|
*x = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:32:15 -08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* Returns the geometry of the range in line ln. Cur1 is the start cursor,
|
|
|
|
* cur2 is the end cursor, NULL means from the start or to the end accordingly.
|
|
|
|
* Assumes that ln is valid, and that at least one of cur1 and cur2 is not NULL.
|
|
|
|
*
|
|
|
|
* @param ln the line to work on.
|
|
|
|
* @param cur1 the start cursor
|
|
|
|
* @param cur2 the end cursor
|
|
|
|
* @return Returns the geometry of the range
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
Evas_Object_Textblock_Item *it1, *it2;
|
|
|
|
Eina_List *rects = NULL;
|
|
|
|
Evas_Textblock_Rectangle *tr;
|
|
|
|
size_t start, end;
|
2011-01-30 02:32:33 -08:00
|
|
|
Eina_Bool switch_items;
|
2011-01-30 02:32:15 -08:00
|
|
|
const Evas_Textblock_Cursor *cur;
|
2011-01-30 02:32:33 -08:00
|
|
|
|
2011-01-30 02:32:15 -08:00
|
|
|
cur = (cur1) ? cur1 : cur2;
|
|
|
|
|
|
|
|
/* Find the first and last items */
|
|
|
|
it1 = it2 = NULL;
|
|
|
|
start = end = 0;
|
|
|
|
EINA_INLIST_FOREACH(ln->items, it)
|
|
|
|
{
|
|
|
|
size_t item_len;
|
|
|
|
item_len = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
|
2011-02-14 05:09:41 -08:00
|
|
|
_ITEM_TEXT(it)->text_props.text_len
|
2011-01-30 02:32:15 -08:00
|
|
|
: 1;
|
|
|
|
if ((!cur1 || (cur1->pos < it->text_pos + item_len)) &&
|
|
|
|
(!cur2 || (cur2->pos >= it->text_pos)))
|
|
|
|
{
|
|
|
|
if (!it1)
|
|
|
|
{
|
|
|
|
it1 = it;
|
2011-01-30 02:35:56 -08:00
|
|
|
start = item_len; /* start stores the first item_len */
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
it2 = it;
|
2011-01-30 02:32:33 -08:00
|
|
|
end = item_len; /* end stores the last item_len */
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:32:33 -08:00
|
|
|
|
|
|
|
/* If we couldn't find even one item, return */
|
|
|
|
if (!it1) return NULL;
|
|
|
|
|
|
|
|
/* If the first item is logically before or equal the second item
|
|
|
|
* we have to set start and end differently than in the other case */
|
|
|
|
if (it1->text_pos <= it2->text_pos)
|
|
|
|
{
|
|
|
|
start = (cur1) ? (cur1->pos - it1->text_pos) : 0;
|
|
|
|
end = (cur2) ? (cur2->pos - it2->text_pos) : end;
|
|
|
|
switch_items = EINA_FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:35:56 -08:00
|
|
|
start = (cur2) ? (cur2->pos - it1->text_pos) : start;
|
2011-01-30 02:32:39 -08:00
|
|
|
end = (cur1) ? (cur1->pos - it2->text_pos) : 0;
|
2011-01-30 02:32:33 -08:00
|
|
|
switch_items = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-01-30 02:32:55 -08:00
|
|
|
/* IMPORTANT: Don't use cur1/cur2 past this point (because they probably
|
|
|
|
* don't make sense anymore. That's why there are start and end),
|
|
|
|
* unless you know what you are doing */
|
2011-01-30 02:32:33 -08:00
|
|
|
|
2011-01-30 02:32:50 -08:00
|
|
|
/* Special case when they share the same item and it's a text item */
|
|
|
|
if ((it1 == it2) && (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT))
|
2011-01-30 02:32:15 -08:00
|
|
|
{
|
|
|
|
Evas_Coord x1, w1, x2, w2;
|
|
|
|
Evas_Coord x, w, y, h;
|
2011-01-30 02:32:50 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ti = _ITEM_TEXT(it1);
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2011-01-30 02:32:50 -08:00
|
|
|
start,
|
|
|
|
&x1, &y, &w1, &h);
|
|
|
|
if (!ret)
|
2011-01-30 02:32:15 -08:00
|
|
|
{
|
2011-01-30 02:32:50 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2011-01-30 02:32:50 -08:00
|
|
|
end,
|
|
|
|
&x2, &y, &w2, &h);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-01-30 02:32:15 -08:00
|
|
|
|
2011-01-30 02:32:50 -08:00
|
|
|
/* Make x2 the one on the right */
|
|
|
|
if (x2 < x1)
|
|
|
|
{
|
|
|
|
Evas_Coord tmp;
|
|
|
|
tmp = x1;
|
|
|
|
x1 = x2;
|
|
|
|
x2 = tmp;
|
|
|
|
|
|
|
|
tmp = w1;
|
|
|
|
w1 = w2;
|
|
|
|
w2 = tmp;
|
|
|
|
}
|
2011-01-30 02:32:27 -08:00
|
|
|
|
|
|
|
#ifdef BIDI_SUPPORT
|
2011-02-14 05:09:41 -08:00
|
|
|
if (ti->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
|
2011-01-30 02:32:50 -08:00
|
|
|
{
|
|
|
|
x = x1 + w1;
|
|
|
|
w = x2 + w2 - x;
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
else
|
2011-01-30 02:32:50 -08:00
|
|
|
#endif
|
2011-01-30 02:32:15 -08:00
|
|
|
{
|
2011-01-30 02:32:50 -08:00
|
|
|
x = x1;
|
|
|
|
w = x2 - x1;
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
if (w > 0)
|
|
|
|
{
|
|
|
|
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
|
|
|
rects = eina_list_append(rects, tr);
|
2011-01-30 02:40:09 -08:00
|
|
|
tr->x = ln->par->x + ln->x + it1->x + x;
|
|
|
|
tr->y = ln->par->y + ln->y;
|
2011-01-30 02:32:15 -08:00
|
|
|
tr->h = ln->h;
|
|
|
|
tr->w = w;
|
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:32:50 -08:00
|
|
|
else if (it1 != it2)
|
2011-01-30 02:32:15 -08:00
|
|
|
{
|
|
|
|
/* Get the middle items */
|
|
|
|
Evas_Coord min_x, max_x;
|
|
|
|
Evas_Coord x, w;
|
|
|
|
it = _ITEM(EINA_INLIST_GET(it1)->next);
|
|
|
|
min_x = max_x = it->x;
|
|
|
|
|
|
|
|
if (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Coord y, h;
|
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
|
|
|
int ret;
|
|
|
|
ti = _ITEM_TEXT(it1);
|
|
|
|
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2011-01-30 02:32:15 -08:00
|
|
|
start,
|
|
|
|
&x, &y, &w, &h);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
/* BUG! Skip the first item */
|
|
|
|
x = w = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:33:06 -08:00
|
|
|
_evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE,
|
2011-01-30 02:32:33 -08:00
|
|
|
switch_items);
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = 0;
|
|
|
|
w = it1->w;
|
2011-01-30 02:33:06 -08:00
|
|
|
_evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE,
|
|
|
|
switch_items);
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
if (w > 0)
|
|
|
|
{
|
|
|
|
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
|
|
|
rects = eina_list_append(rects, tr);
|
2011-01-30 02:40:09 -08:00
|
|
|
tr->x = ln->par->x + ln->x + it1->x + x;
|
|
|
|
tr->y = ln->par->y + ln->y;
|
2011-01-30 02:32:15 -08:00
|
|
|
tr->h = ln->h;
|
|
|
|
tr->w = w;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (it && (it != it2))
|
|
|
|
{
|
2011-01-30 02:33:19 -08:00
|
|
|
max_x = it->x + it->adv;
|
2011-01-30 02:32:15 -08:00
|
|
|
it = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(it)->next;
|
|
|
|
}
|
|
|
|
if (min_x != max_x)
|
|
|
|
{
|
|
|
|
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
|
|
|
rects = eina_list_append(rects, tr);
|
2011-01-30 02:40:09 -08:00
|
|
|
tr->x = ln->par->x + ln->x + min_x;
|
|
|
|
tr->y = ln->par->y + ln->y;
|
2011-01-30 02:32:15 -08:00
|
|
|
tr->h = ln->h;
|
|
|
|
tr->w = max_x - min_x;
|
|
|
|
}
|
|
|
|
if (it2->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Coord y, h;
|
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
|
|
|
int ret;
|
|
|
|
ti = _ITEM_TEXT(it2);
|
|
|
|
|
2011-01-30 02:34:18 -08:00
|
|
|
ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-04-07 09:25:56 -07:00
|
|
|
&ti->text_props,
|
2011-01-30 02:32:15 -08:00
|
|
|
end,
|
|
|
|
&x, &y, &w, &h);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
/* BUG! skip the last item */
|
|
|
|
x = w = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-30 02:33:06 -08:00
|
|
|
_evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE,
|
2011-01-30 02:32:33 -08:00
|
|
|
switch_items);
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = 0;
|
|
|
|
w = it2->w;
|
2011-01-30 02:33:06 -08:00
|
|
|
_evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE,
|
|
|
|
switch_items);
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
if (w > 0)
|
|
|
|
{
|
|
|
|
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
|
|
|
rects = eina_list_append(rects, tr);
|
2011-01-30 02:40:09 -08:00
|
|
|
tr->x = ln->par->x + ln->x + it2->x + x;
|
|
|
|
tr->y = ln->par->y + ln->y;
|
2011-01-30 02:32:15 -08:00
|
|
|
tr->h = ln->h;
|
|
|
|
tr->w = w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rects;
|
|
|
|
}
|
2008-10-21 09:31:05 -07:00
|
|
|
EAPI Eina_List *
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2011-01-30 02:32:15 -08:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln1, *ln2;
|
|
|
|
Evas_Object_Textblock_Item *it1, *it2;
|
2008-10-21 09:31:05 -07:00
|
|
|
Eina_List *rects = NULL;
|
2005-09-09 07:19:06 -07:00
|
|
|
Evas_Textblock_Rectangle *tr;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-01-30 02:32:15 -08:00
|
|
|
if (!cur1 || !cur1->node) return NULL;
|
|
|
|
if (!cur2 || !cur2->node) return NULL;
|
2005-09-09 07:19:06 -07:00
|
|
|
if (cur1->obj != cur2->obj) return NULL;
|
2011-01-30 02:32:15 -08:00
|
|
|
o = (Evas_Object_Textblock *)(cur1->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur1->obj);
|
2005-10-27 19:56:27 -07:00
|
|
|
if (evas_textblock_cursor_compare(cur1, cur2) > 0)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2008-02-08 14:35:19 -08:00
|
|
|
const Evas_Textblock_Cursor *tc;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-09-09 07:19:06 -07:00
|
|
|
tc = cur1;
|
|
|
|
cur1 = cur2;
|
|
|
|
cur2 = tc;
|
|
|
|
}
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2011-01-30 02:32:15 -08:00
|
|
|
ln1 = ln2 = NULL;
|
|
|
|
it1 = it2 = NULL;
|
|
|
|
_find_layout_item_match(cur1, &ln1, &it1);
|
|
|
|
if (!ln1 || !it1) return NULL;
|
|
|
|
_find_layout_item_match(cur2, &ln2, &it2);
|
|
|
|
if (!ln2 || !it2) return NULL;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2011-01-30 02:32:15 -08:00
|
|
|
if (ln1 == ln2)
|
2005-09-09 07:19:06 -07:00
|
|
|
{
|
2011-01-30 02:32:15 -08:00
|
|
|
rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1,
|
|
|
|
cur1, cur2);
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-14 08:14:26 -08:00
|
|
|
Evas_Object_Textblock_Line *plni, *lni;
|
2011-01-30 02:32:15 -08:00
|
|
|
Eina_List *rects2 = NULL;
|
|
|
|
/* Handle the first line */
|
|
|
|
rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1,
|
|
|
|
cur1, NULL);
|
|
|
|
|
|
|
|
/* Handle the lines between the first and the last line */
|
|
|
|
lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(ln1)->next;
|
2011-02-14 08:14:26 -08:00
|
|
|
if (!lni && (ln1->par != ln2->par))
|
|
|
|
{
|
|
|
|
lni = ((Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(ln1->par)->next)->lines;
|
|
|
|
}
|
2011-01-30 02:32:15 -08:00
|
|
|
while (lni && (lni != ln2))
|
|
|
|
{
|
2005-09-09 07:19:06 -07:00
|
|
|
tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
|
2008-10-21 09:31:05 -07:00
|
|
|
rects = eina_list_append(rects, tr);
|
2011-02-14 08:14:26 -08:00
|
|
|
tr->x = lni->par->x + lni->x;
|
|
|
|
tr->y = lni->par->y + lni->y;
|
2011-01-30 02:32:15 -08:00
|
|
|
tr->h = lni->h;
|
|
|
|
tr->w = lni->w;
|
2011-02-14 08:14:26 -08:00
|
|
|
plni = lni;
|
2011-01-30 02:32:15 -08:00
|
|
|
lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(lni)->next;
|
2011-02-14 08:14:26 -08:00
|
|
|
if (!lni && (plni->par != ln2->par))
|
|
|
|
{
|
|
|
|
lni = ((Evas_Object_Textblock_Paragraph *)
|
|
|
|
EINA_INLIST_GET(plni->par)->next)->lines;
|
|
|
|
}
|
2011-01-30 02:32:15 -08:00
|
|
|
}
|
|
|
|
rects2 = _evas_textblock_cursor_range_in_line_geometry_get(ln2,
|
|
|
|
NULL, cur2);
|
|
|
|
rects = eina_list_merge(rects, rects2);
|
2005-09-09 07:19:06 -07:00
|
|
|
}
|
|
|
|
return rects;
|
|
|
|
}
|
|
|
|
|
2010-04-25 05:40:26 -07:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
Evas_Object_Textblock_Line *ln = NULL;
|
2011-02-23 08:49:31 -08:00
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
Evas_Object_Textblock_Item *it = NULL;
|
2010-04-25 05:40:26 -07:00
|
|
|
Evas_Coord x, y, w, h;
|
|
|
|
|
2011-01-30 02:31:58 -08:00
|
|
|
if (!cur || !evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE;
|
2010-04-25 05:40:26 -07:00
|
|
|
o = (Evas_Object_Textblock *)(cur->obj->object_data);
|
|
|
|
if (!o->formatted.valid) _relayout(cur->obj);
|
2011-01-30 02:31:58 -08:00
|
|
|
if (!evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE;
|
2011-02-23 08:50:59 -08:00
|
|
|
_find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it);
|
2011-02-23 08:49:31 -08:00
|
|
|
fi = _ITEM_FORMAT(it);
|
2011-01-30 02:31:58 -08:00
|
|
|
if ((!ln) || (!fi)) return EINA_FALSE;
|
2011-01-30 02:40:09 -08:00
|
|
|
x = ln->par->x + ln->x + fi->parent.x;
|
|
|
|
y = ln->par->y + ln->y + ln->baseline + fi->y;
|
2011-01-30 02:31:16 -08:00
|
|
|
w = fi->parent.w;
|
|
|
|
h = fi->parent.h;
|
2010-04-25 05:40:26 -07:00
|
|
|
if (cx) *cx = x;
|
|
|
|
if (cy) *cy = y;
|
|
|
|
if (cw) *cw = w;
|
|
|
|
if (ch) *ch = h;
|
2011-01-30 02:31:58 -08:00
|
|
|
return EINA_TRUE;
|
2010-04-25 05:40:26 -07:00
|
|
|
}
|
|
|
|
|
2009-05-14 05:52:44 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur)
|
|
|
|
{
|
2010-08-09 09:24:17 -07:00
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
Evas_Textblock_Cursor cur2;
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!cur) return EINA_FALSE;
|
2010-08-16 02:18:09 -07:00
|
|
|
|
2010-08-09 09:24:17 -07:00
|
|
|
evas_textblock_cursor_copy(cur, &cur2);
|
|
|
|
evas_textblock_cursor_line_char_last(&cur2);
|
|
|
|
if (cur2.pos == cur->pos)
|
|
|
|
{
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
}
|
|
|
|
return ret;
|
2009-05-14 05:52:44 -07:00
|
|
|
}
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
/* general controls */
|
2009-06-17 03:01:52 -07:00
|
|
|
EAPI Eina_Bool
|
2008-02-08 14:35:19 -08:00
|
|
|
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)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Line *ln;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-09-20 09:59:39 -07:00
|
|
|
TB_HEAD_RETURN(0);
|
2005-08-20 01:01:59 -07:00
|
|
|
ln = _find_layout_line_num(obj, line);
|
2009-06-17 03:01:52 -07:00
|
|
|
if (!ln) return EINA_FALSE;
|
2011-01-30 02:40:09 -08:00
|
|
|
if (cx) *cx = ln->par->x + ln->x;
|
|
|
|
if (cy) *cy = ln->par->y + ln->y;
|
2005-08-20 01:01:59 -07:00
|
|
|
if (cw) *cw = ln->w;
|
|
|
|
if (ch) *ch = ln->h;
|
2009-06-17 03:01:52 -07:00
|
|
|
return EINA_TRUE;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_clear(Evas_Object *obj)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
2008-10-21 09:31:05 -07:00
|
|
|
Eina_List *l;
|
|
|
|
Evas_Textblock_Cursor *cur;
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
TB_HEAD();
|
2011-04-14 05:13:20 -07:00
|
|
|
if (o->paragraphs)
|
|
|
|
{
|
|
|
|
_paragraphs_free(obj, o->paragraphs);
|
|
|
|
o->paragraphs = NULL;
|
|
|
|
}
|
|
|
|
|
2005-08-20 01:01:59 -07:00
|
|
|
_nodes_clear(obj);
|
2010-03-04 08:22:28 -08:00
|
|
|
o->cursor->node = NULL;
|
|
|
|
o->cursor->pos = 0;
|
2008-10-21 09:31:05 -07:00
|
|
|
EINA_LIST_FOREACH(o->cursors, l, cur)
|
2005-08-16 01:12:14 -07:00
|
|
|
{
|
2005-08-20 01:01:59 -07:00
|
|
|
cur->node = NULL;
|
|
|
|
cur->pos = 0;
|
2010-08-09 09:24:17 -07:00
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
}
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-03 06:07:00 -07:00
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_object_textblock_size_formatted_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
|
2005-08-20 01:01:59 -07:00
|
|
|
{
|
|
|
|
TB_HEAD();
|
2005-08-27 23:41:54 -07:00
|
|
|
if (!o->formatted.valid) _relayout(obj);
|
|
|
|
if (w) *w = o->formatted.w;
|
|
|
|
if (h) *h = o->formatted.h;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_object_textblock_size_native_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
|
2005-08-27 23:41:54 -07:00
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (!o->native.valid)
|
|
|
|
{
|
2009-09-03 22:13:19 -07:00
|
|
|
_layout(obj,
|
2005-08-27 23:41:54 -07:00
|
|
|
1,
|
|
|
|
-1, -1,
|
|
|
|
&o->native.w, &o->native.h);
|
|
|
|
o->native.valid = 1;
|
2011-01-30 02:41:13 -08:00
|
|
|
o->content_changed = 0;
|
2011-04-27 05:41:26 -07:00
|
|
|
o->format_changed = EINA_FALSE;
|
2005-08-27 23:41:54 -07:00
|
|
|
}
|
|
|
|
if (w) *w = o->native.w;
|
|
|
|
if (h) *h = o->native.h;
|
|
|
|
}
|
|
|
|
|
2006-01-06 15:05:17 -08:00
|
|
|
EAPI void
|
2008-02-08 14:35:19 -08:00
|
|
|
evas_object_textblock_style_insets_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
|
2005-08-27 23:41:54 -07:00
|
|
|
{
|
|
|
|
TB_HEAD();
|
|
|
|
if (!o->formatted.valid) _relayout(obj);
|
|
|
|
if (l) *l = o->style_pad.l;
|
|
|
|
if (r) *r = o->style_pad.r;
|
|
|
|
if (t) *t = o->style_pad.t;
|
|
|
|
if (b) *b = o->style_pad.b;
|
2005-08-20 01:01:59 -07:00
|
|
|
}
|
2005-08-03 06:07:00 -07:00
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
/* all nice and private */
|
|
|
|
static void
|
|
|
|
evas_object_textblock_init(Evas_Object *obj)
|
|
|
|
{
|
2005-08-05 03:08:05 -07:00
|
|
|
Evas_Object_Textblock *o;
|
2011-05-05 04:06:06 -07:00
|
|
|
#ifdef HAVE_LINEBREAK
|
|
|
|
static Eina_Bool linebreak_init = EINA_FALSE;
|
|
|
|
if (!linebreak_init)
|
|
|
|
{
|
|
|
|
linebreak_init = EINA_TRUE;
|
|
|
|
init_linebreak();
|
|
|
|
}
|
|
|
|
#endif
|
2005-10-14 22:19:11 -07:00
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
/* alloc image ob, setup methods and default values */
|
|
|
|
obj->object_data = evas_object_textblock_new();
|
|
|
|
/* set up default settings for this kind of object */
|
|
|
|
obj->cur.color.r = 255;
|
|
|
|
obj->cur.color.g = 255;
|
|
|
|
obj->cur.color.b = 255;
|
|
|
|
obj->cur.color.a = 255;
|
|
|
|
obj->cur.geometry.x = 0.0;
|
|
|
|
obj->cur.geometry.y = 0.0;
|
|
|
|
obj->cur.geometry.w = 0.0;
|
|
|
|
obj->cur.geometry.h = 0.0;
|
|
|
|
obj->cur.layer = 0;
|
|
|
|
/* set up object-specific settings */
|
|
|
|
obj->prev = obj->cur;
|
|
|
|
/* set up methods (compulsory) */
|
|
|
|
obj->func = &object_func;
|
|
|
|
obj->type = o_type;
|
2005-08-05 03:08:05 -07:00
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
o->cursor->obj = obj;
|
2011-02-14 06:17:12 -08:00
|
|
|
o->newline_is_ps = EINA_TRUE;
|
2005-01-08 02:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
evas_object_textblock_new(void)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2005-05-21 19:49:50 -07:00
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
/* alloc obj private data */
|
2010-11-26 02:01:18 -08:00
|
|
|
EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_textblock", Evas_Object_Textblock, 64, NULL);
|
|
|
|
o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Textblock);
|
|
|
|
if (!o) return NULL;
|
|
|
|
EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Textblock);
|
2005-01-08 02:02:18 -08:00
|
|
|
o->magic = MAGIC_OBJ_TEXTBLOCK;
|
2005-08-05 03:08:05 -07:00
|
|
|
o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor));
|
2010-08-09 09:24:17 -07:00
|
|
|
_format_command_init();
|
2005-01-08 02:02:18 -08:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
evas_object_textblock_free(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
2005-10-27 19:56:27 -07:00
|
|
|
evas_object_textblock_clear(obj);
|
|
|
|
evas_object_textblock_style_set(obj, NULL);
|
2005-01-08 02:02:18 -08:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2010-03-04 08:22:28 -08:00
|
|
|
free(o->cursor);
|
2005-08-05 03:08:05 -07:00
|
|
|
while (o->cursors)
|
|
|
|
{
|
|
|
|
Evas_Textblock_Cursor *cur;
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-05 03:08:05 -07:00
|
|
|
cur = (Evas_Textblock_Cursor *)o->cursors->data;
|
2008-10-21 09:31:05 -07:00
|
|
|
o->cursors = eina_list_remove_list(o->cursors, o->cursors);
|
2005-08-05 03:08:05 -07:00
|
|
|
free(cur);
|
|
|
|
}
|
2008-10-22 01:57:30 -07:00
|
|
|
if (o->repch) eina_stringshare_del(o->repch);
|
2005-01-08 02:02:18 -08:00
|
|
|
o->magic = 0;
|
2010-11-26 02:01:18 -08:00
|
|
|
EVAS_MEMPOOL_FREE(_mp_obj, o);
|
|
|
|
_format_command_shutdown();
|
2005-01-08 02:02:18 -08:00
|
|
|
}
|
|
|
|
|
2010-07-28 05:00:41 -07:00
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
static void
|
|
|
|
evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
|
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
2005-01-08 02:02:18 -08:00
|
|
|
Evas_Object_Textblock *o;
|
2005-08-16 01:12:14 -07:00
|
|
|
int i, j;
|
|
|
|
unsigned char r = 0, g = 0, b = 0, a = 0;
|
|
|
|
unsigned char r2 = 0, g2 = 0, b2 = 0, a2 = 0;
|
|
|
|
unsigned char r3 = 0, g3 = 0, b3 = 0, a3 = 0;
|
2010-02-03 23:41:07 -08:00
|
|
|
int cx, cy, cw, ch, clip;
|
2005-08-16 01:12:14 -07:00
|
|
|
const char vals[5][5] =
|
|
|
|
{
|
|
|
|
{0, 1, 2, 1, 0},
|
|
|
|
{1, 3, 4, 3, 1},
|
|
|
|
{2, 4, 5, 4, 2},
|
|
|
|
{1, 3, 4, 3, 1},
|
|
|
|
{0, 1, 2, 1, 0}
|
|
|
|
};
|
2005-08-30 08:19:39 -07:00
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
/* render object to surface with context, and offxet by x,y */
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
obj->layer->evas->engine.func->context_multiplier_unset(output,
|
|
|
|
context);
|
2011-03-29 06:52:42 -07:00
|
|
|
/* FIXME: This clipping is just until we fix inset handling correctly. */
|
|
|
|
ENFN->context_clip_clip(output, context,
|
|
|
|
obj->cur.geometry.x + x,
|
|
|
|
obj->cur.geometry.y + y,
|
|
|
|
obj->cur.geometry.w,
|
|
|
|
obj->cur.geometry.h);
|
2010-02-03 23:41:07 -08:00
|
|
|
clip = ENFN->context_clip_get(output, context, &cx, &cy, &cw, &ch);
|
2010-08-17 10:55:48 -07:00
|
|
|
/* If there are no paragraphs and thus there are no lines,
|
|
|
|
* there's nothing left to do. */
|
|
|
|
if (!o->paragraphs) return;
|
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
#define ITEM_WALK() \
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par) \
|
2005-08-16 01:12:14 -07:00
|
|
|
{ \
|
2011-04-11 06:44:01 -07:00
|
|
|
if (!par->visible) continue; \
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(par->lines, ln) \
|
2010-02-03 23:41:07 -08:00
|
|
|
{ \
|
2011-01-30 02:39:47 -08:00
|
|
|
Evas_Object_Textblock_Item *itr; \
|
2010-08-26 02:22:31 -07:00
|
|
|
\
|
2011-01-30 02:39:47 -08:00
|
|
|
if (clip) \
|
2010-02-03 23:41:07 -08:00
|
|
|
{ \
|
2011-01-30 02:40:09 -08:00
|
|
|
if ((obj->cur.geometry.y + y + ln->par->y + ln->y + ln->h) < (cy - 20)) \
|
2011-01-30 02:39:47 -08:00
|
|
|
continue; \
|
2011-01-30 02:40:09 -08:00
|
|
|
if ((obj->cur.geometry.y + y + ln->par->y + ln->y) > (cy + ch + 20)) \
|
2011-01-30 02:39:47 -08:00
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
EINA_INLIST_FOREACH(ln->items, itr) \
|
|
|
|
{ \
|
|
|
|
int yoff; \
|
2011-01-30 02:40:47 -08:00
|
|
|
yoff = ln->baseline; \
|
|
|
|
if (itr->format->valign != -1.0) \
|
|
|
|
yoff = (itr->format->valign * (double)(ln->h - itr->h)) + \
|
|
|
|
(itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? \
|
|
|
|
_ITEM_TEXT(itr)->baseline : ln->baseline; \
|
|
|
|
if (clip) \
|
2011-01-30 02:31:28 -08:00
|
|
|
{ \
|
2011-01-30 02:40:47 -08:00
|
|
|
if ((obj->cur.geometry.x + x + ln->par->x + ln->x + itr->x + itr->w) < (cx - 20)) \
|
|
|
|
continue; \
|
|
|
|
if ((obj->cur.geometry.x + x + ln->par->x + ln->x + itr->x) > (cx + cw + 20)) \
|
|
|
|
break; \
|
2011-01-30 02:31:28 -08:00
|
|
|
} \
|
2011-01-30 02:39:47 -08:00
|
|
|
do
|
2010-08-17 10:55:48 -07:00
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
#define ITEM_WALK_END() \
|
2011-01-30 02:39:47 -08:00
|
|
|
while (0); \
|
|
|
|
} \
|
2010-08-26 02:22:31 -07:00
|
|
|
} \
|
2011-01-30 02:31:40 -08:00
|
|
|
} \
|
|
|
|
do {} while(0)
|
2005-08-16 01:12:14 -07:00
|
|
|
#define COLOR_SET(col) \
|
2010-08-26 02:22:31 -07:00
|
|
|
ENFN->context_color_set(output, context, \
|
2011-01-30 02:40:47 -08:00
|
|
|
(obj->cur.cache.clip.r * ti->parent.format->color.col.r) / 255, \
|
|
|
|
(obj->cur.cache.clip.g * ti->parent.format->color.col.g) / 255, \
|
|
|
|
(obj->cur.cache.clip.b * ti->parent.format->color.col.b) / 255, \
|
|
|
|
(obj->cur.cache.clip.a * ti->parent.format->color.col.a) / 255);
|
2005-08-16 01:12:14 -07:00
|
|
|
#define COLOR_SET_AMUL(col, amul) \
|
2010-08-26 02:22:31 -07:00
|
|
|
ENFN->context_color_set(output, context, \
|
2011-01-30 02:40:47 -08:00
|
|
|
(obj->cur.cache.clip.r * ti->parent.format->color.col.r * (amul)) / 65025, \
|
|
|
|
(obj->cur.cache.clip.g * ti->parent.format->color.col.g * (amul)) / 65025, \
|
|
|
|
(obj->cur.cache.clip.b * ti->parent.format->color.col.b * (amul)) / 65025, \
|
|
|
|
(obj->cur.cache.clip.a * ti->parent.format->color.col.a * (amul)) / 65025);
|
2011-01-30 02:31:28 -08:00
|
|
|
#define DRAW_TEXT(ox, oy) \
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->font.font) ENFN->font_draw(output, context, surface, ti->parent.format->font.font, \
|
2011-01-30 02:40:09 -08:00
|
|
|
obj->cur.geometry.x + ln->par->x + ln->x + ti->parent.x + x + (ox), \
|
|
|
|
obj->cur.geometry.y + ln->par->y + ln->y + yoff + y + (oy), \
|
2011-04-13 01:36:57 -07:00
|
|
|
ti->parent.w, ti->parent.h, ti->parent.w, ti->parent.h, \
|
2011-04-14 04:37:06 -07:00
|
|
|
&ti->text_props);
|
2008-10-20 06:07:05 -07:00
|
|
|
#define ITEM_WALK_LINE_SKIP_DROP() \
|
2011-01-30 02:40:09 -08:00
|
|
|
if ((ln->par->y + ln->y + ln->h) <= 0) continue; \
|
|
|
|
if (ln->par->y + ln->y > obj->cur.geometry.h) break
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-01-30 02:31:28 -08:00
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
/* backing */
|
2011-01-30 02:31:28 -08:00
|
|
|
#define DRAW_RECT(ox, oy, ow, oh, or, og, ob, oa) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
ENFN->context_color_set(output, \
|
|
|
|
context, \
|
|
|
|
(obj->cur.cache.clip.r * or) / 255, \
|
|
|
|
(obj->cur.cache.clip.g * og) / 255, \
|
|
|
|
(obj->cur.cache.clip.b * ob) / 255, \
|
|
|
|
(obj->cur.cache.clip.a * oa) / 255); \
|
|
|
|
ENFN->rectangle_draw(output, \
|
|
|
|
context, \
|
|
|
|
surface, \
|
2011-01-30 02:40:09 -08:00
|
|
|
obj->cur.geometry.x + ln->par->x + ln->x + x + (ox), \
|
|
|
|
obj->cur.geometry.y + ln->par->y + ln->y + y + (oy), \
|
2011-01-30 02:31:28 -08:00
|
|
|
(ow), \
|
|
|
|
(oh)); \
|
|
|
|
} \
|
|
|
|
while (0)
|
|
|
|
|
2011-01-30 02:32:03 -08:00
|
|
|
#define DRAW_FORMAT(oname, oy, oh, or, og, ob, oa) \
|
|
|
|
do \
|
|
|
|
{ \
|
2011-01-30 02:40:47 -08:00
|
|
|
if (itr->format->oname) \
|
2011-01-30 02:32:03 -08:00
|
|
|
{ \
|
2011-01-30 02:40:47 -08:00
|
|
|
or = itr->format->color.oname.r; \
|
|
|
|
og = itr->format->color.oname.g; \
|
|
|
|
ob = itr->format->color.oname.b; \
|
|
|
|
oa = itr->format->color.oname.a; \
|
2011-04-28 05:12:57 -07:00
|
|
|
if (!EINA_INLIST_GET(itr)->next) \
|
|
|
|
{ \
|
|
|
|
DRAW_RECT(itr->x, oy, itr->w, oh, or, og, ob, oa); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
DRAW_RECT(itr->x, oy, itr->adv, oh, or, og, ob, oa); \
|
|
|
|
} \
|
2011-01-30 02:40:47 -08:00
|
|
|
} \
|
2011-01-30 02:32:03 -08:00
|
|
|
} \
|
|
|
|
while (0)
|
|
|
|
|
|
|
|
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK()
|
|
|
|
{
|
|
|
|
ITEM_WALK_LINE_SKIP_DROP();
|
|
|
|
|
2011-01-30 02:32:03 -08:00
|
|
|
DRAW_FORMAT(backing, 0, ln->h, r, g, b, a);
|
2005-08-16 01:12:14 -07:00
|
|
|
}
|
|
|
|
ITEM_WALK_END();
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-03-29 06:52:35 -07:00
|
|
|
/* There are size adjustments that depend on the styles drawn here back
|
|
|
|
* in "_text_item_update_sizes" should not modify one without the other. */
|
|
|
|
|
2010-07-28 05:00:41 -07:00
|
|
|
/* prepare everything for text draw */
|
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
/* shadows */
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK()
|
2005-08-08 02:01:07 -07:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
int shad_dst, shad_sz, dx, dy, haveshad;
|
2011-01-30 02:40:47 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK_LINE_SKIP_DROP();
|
2011-01-30 02:40:47 -08:00
|
|
|
ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
|
2011-01-30 02:31:28 -08:00
|
|
|
if (!ti) continue;
|
|
|
|
|
2011-04-13 02:29:45 -07:00
|
|
|
shad_dst = shad_sz = dx = dy = haveshad = 0;
|
2011-04-11 05:05:59 -07:00
|
|
|
switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-11 05:05:59 -07:00
|
|
|
case EVAS_TEXT_STYLE_SHADOW:
|
|
|
|
case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
|
|
|
|
shad_dst = 1;
|
2011-04-13 02:29:45 -07:00
|
|
|
haveshad = 1;
|
2011-04-11 05:05:59 -07:00
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
|
|
|
|
case EVAS_TEXT_STYLE_FAR_SHADOW:
|
|
|
|
shad_dst = 2;
|
2011-04-13 02:29:45 -07:00
|
|
|
haveshad = 1;
|
2011-04-11 05:05:59 -07:00
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
|
|
|
|
shad_dst = 2;
|
|
|
|
shad_sz = 2;
|
2011-04-13 02:29:45 -07:00
|
|
|
haveshad = 1;
|
2011-04-11 05:05:59 -07:00
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SOFT_SHADOW:
|
|
|
|
shad_dst = 1;
|
|
|
|
shad_sz = 2;
|
2011-04-13 02:29:45 -07:00
|
|
|
haveshad = 1;
|
2011-04-11 05:05:59 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2011-01-30 02:31:28 -08:00
|
|
|
}
|
2011-04-13 02:29:45 -07:00
|
|
|
if (haveshad)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
if (shad_dst > 0)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
|
|
|
|
{
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
|
|
|
|
dx = 1;
|
|
|
|
dy = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
|
|
|
|
dx = 0;
|
|
|
|
dy = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
|
|
|
|
dx = -1;
|
|
|
|
dy = 1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
|
|
|
|
dx = -1;
|
|
|
|
dy = 0;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
|
|
|
|
dx = -1;
|
|
|
|
dy = -1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
|
|
|
|
dx = 0;
|
|
|
|
dy = -1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
|
|
|
|
dx = 1;
|
|
|
|
dy = -1;
|
|
|
|
break;
|
|
|
|
case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
|
|
|
|
dx = 1;
|
|
|
|
dy = 0;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dx *= shad_dst;
|
|
|
|
dy *= shad_dst;
|
2011-01-30 02:31:28 -08:00
|
|
|
}
|
2011-04-13 02:29:45 -07:00
|
|
|
switch (shad_sz)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
case 0:
|
|
|
|
COLOR_SET(shadow);
|
|
|
|
DRAW_TEXT(dx, dy);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
for (j = 0; j < 5; j++)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
for (i = 0; i < 5; i++)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
2011-04-13 02:29:45 -07:00
|
|
|
if (vals[i][j] != 0)
|
|
|
|
{
|
|
|
|
COLOR_SET_AMUL(shadow, vals[i][j] * 50);
|
|
|
|
DRAW_TEXT(i - 2 + dx, j - 2 + dy);
|
|
|
|
}
|
2011-01-30 02:31:28 -08:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 02:29:45 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2011-01-30 02:31:28 -08:00
|
|
|
}
|
|
|
|
}
|
the textblock actually works.
so far the following works:
o = evas_object_textblock_add(evas);
evas_object_move(o, 10, 40);
evas_object_resize(o, win_w - 20, win_h - 50);
evas_object_textblock_format_insert(o, "color=#000000ff");
evas_object_textblock_format_insert(o, "font=/usr/local/share/expedite/data/Vera.ttf size=10");
evas_object_textblock_text_insert(o, "This is 1 line. ");
evas_object_textblock_text_insert(o, "And some more text. ");
evas_object_textblock_format_insert(o, "size=20");
evas_object_textblock_format_insert(o, "color=#f80");
evas_object_textblock_text_insert(o, "Bigger orange text.");
evas_object_textblock_format_insert(o, "size=8");
evas_object_textblock_format_insert(o, "color=#0000ff88");
evas_object_textblock_format_insert(o, "\n");
evas_object_textblock_text_insert(o, "A second line of transparent blue.");
evas_object_show(o);
i need to implement alignment handling next...
SVN revision: 13135
2005-01-30 02:22:47 -08:00
|
|
|
}
|
2005-08-16 01:12:14 -07:00
|
|
|
ITEM_WALK_END();
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
/* glows */
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK()
|
2005-08-16 01:12:14 -07:00
|
|
|
{
|
2011-01-30 02:40:47 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK_LINE_SKIP_DROP();
|
2011-01-30 02:40:47 -08:00
|
|
|
ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
|
2011-01-30 02:31:28 -08:00
|
|
|
if (!ti) continue;
|
|
|
|
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->style == EVAS_TEXT_STYLE_GLOW)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
|
|
|
for (j = 0; j < 5; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
if (vals[i][j] != 0)
|
|
|
|
{
|
|
|
|
COLOR_SET_AMUL(glow, vals[i][j] * 50);
|
|
|
|
DRAW_TEXT(i - 2, j - 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
COLOR_SET(glow2);
|
|
|
|
DRAW_TEXT(-1, 0);
|
|
|
|
DRAW_TEXT(1, 0);
|
|
|
|
DRAW_TEXT(0, -1);
|
|
|
|
DRAW_TEXT(0, 1);
|
|
|
|
}
|
2005-08-16 01:12:14 -07:00
|
|
|
}
|
|
|
|
ITEM_WALK_END();
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2005-08-16 01:12:14 -07:00
|
|
|
/* outlines */
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK()
|
2005-08-16 01:12:14 -07:00
|
|
|
{
|
2011-01-30 02:40:47 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK_LINE_SKIP_DROP();
|
2011-01-30 02:40:47 -08:00
|
|
|
ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
|
2011-01-30 02:31:28 -08:00
|
|
|
if (!ti) continue;
|
|
|
|
|
2011-01-30 02:40:47 -08:00
|
|
|
if ((ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE) ||
|
|
|
|
(ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
|
|
|
|
(ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
|
|
|
COLOR_SET(outline);
|
|
|
|
DRAW_TEXT(-1, 0);
|
|
|
|
DRAW_TEXT(1, 0);
|
|
|
|
DRAW_TEXT(0, -1);
|
|
|
|
DRAW_TEXT(0, 1);
|
|
|
|
}
|
2011-01-30 02:40:47 -08:00
|
|
|
else if (ti->parent.format->style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
|
2011-01-30 02:31:28 -08:00
|
|
|
{
|
|
|
|
for (j = 0; j < 5; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
|
|
|
|
{
|
|
|
|
COLOR_SET_AMUL(outline, vals[i][j] * 50);
|
|
|
|
DRAW_TEXT(i - 2, j - 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-26 00:04:20 -08:00
|
|
|
}
|
2005-08-16 01:12:14 -07:00
|
|
|
ITEM_WALK_END();
|
2009-09-03 22:13:19 -07:00
|
|
|
|
2011-01-30 02:31:28 -08:00
|
|
|
/* normal text and lines */
|
|
|
|
ITEM_WALK()
|
|
|
|
{
|
2011-01-30 02:40:47 -08:00
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
2011-01-30 02:31:28 -08:00
|
|
|
ITEM_WALK_LINE_SKIP_DROP();
|
2011-01-30 02:40:47 -08:00
|
|
|
ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
|
2011-01-30 02:31:28 -08:00
|
|
|
/* NORMAL TEXT */
|
|
|
|
if (ti)
|
|
|
|
{
|
|
|
|
COLOR_SET(normal);
|
|
|
|
DRAW_TEXT(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* STRIKETHROUGH */
|
2011-01-30 02:32:03 -08:00
|
|
|
DRAW_FORMAT(strikethrough, (ln->h / 2), 1, r, g, b, a);
|
2011-01-30 02:31:28 -08:00
|
|
|
|
|
|
|
/* UNDERLINE */
|
2011-01-30 02:32:03 -08:00
|
|
|
DRAW_FORMAT(underline, ln->baseline + 1, 1, r2, g2, b2, a2);
|
2011-01-30 02:31:28 -08:00
|
|
|
|
|
|
|
/* UNDERLINE2 */
|
2011-01-30 02:32:03 -08:00
|
|
|
DRAW_FORMAT(underline2, ln->baseline + 3, 1, r3, g3, b3, a3);
|
2005-08-16 01:12:14 -07:00
|
|
|
}
|
|
|
|
ITEM_WALK_END();
|
2005-01-08 02:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
evas_object_textblock_render_pre(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
int is_v, was_v;
|
|
|
|
|
|
|
|
/* dont pre-render the obj twice! */
|
|
|
|
if (obj->pre_render_done) return;
|
|
|
|
obj->pre_render_done = 1;
|
|
|
|
/* pre-render phase. this does anything an object needs to do just before */
|
|
|
|
/* rendering. this could mean loading the image data, retrieving it from */
|
|
|
|
/* elsewhere, decoding video etc. */
|
|
|
|
/* then when this is done the object needs to figure if it changed and */
|
|
|
|
/* if so what and where and add the appropriate redraw textblocks */
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-04-27 05:41:26 -07:00
|
|
|
if ((o->changed) || (o->content_changed) || (o->format_changed) ||
|
2011-03-30 03:31:29 -07:00
|
|
|
((obj->cur.geometry.w != o->last_w) ||
|
2011-03-30 03:38:02 -07:00
|
|
|
(((o->valign != 0.0) || (o->have_ellipsis)) &&
|
|
|
|
(obj->cur.geometry.h != o->last_h))))
|
2005-08-05 03:08:05 -07:00
|
|
|
{
|
2011-04-04 04:14:38 -07:00
|
|
|
_relayout(obj);
|
2005-11-23 20:40:14 -08:00
|
|
|
o->redraw = 0;
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
2005-08-16 02:25:48 -07:00
|
|
|
is_v = evas_object_is_visible(obj);
|
|
|
|
was_v = evas_object_was_visible(obj);
|
2005-08-08 05:43:59 -07:00
|
|
|
goto done;
|
2005-08-05 03:08:05 -07:00
|
|
|
}
|
2005-08-27 23:41:54 -07:00
|
|
|
if (o->redraw)
|
|
|
|
{
|
|
|
|
o->redraw = 0;
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
2005-08-27 23:41:54 -07:00
|
|
|
is_v = evas_object_is_visible(obj);
|
|
|
|
was_v = evas_object_was_visible(obj);
|
|
|
|
goto done;
|
|
|
|
}
|
2005-01-08 02:02:18 -08:00
|
|
|
/* if someone is clipping this obj - go calculate the clipper */
|
|
|
|
if (obj->cur.clipper)
|
|
|
|
{
|
2005-04-03 07:22:17 -07:00
|
|
|
if (obj->cur.cache.clip.dirty)
|
|
|
|
evas_object_clip_recalc(obj->cur.clipper);
|
2005-01-08 02:02:18 -08:00
|
|
|
obj->cur.clipper->func->render_pre(obj->cur.clipper);
|
|
|
|
}
|
|
|
|
/* now figure what changed and add draw rects */
|
|
|
|
/* if it just became visible or invisible */
|
|
|
|
is_v = evas_object_is_visible(obj);
|
|
|
|
was_v = evas_object_was_visible(obj);
|
|
|
|
if (is_v != was_v)
|
|
|
|
{
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
|
2005-01-08 02:02:18 -08:00
|
|
|
goto done;
|
|
|
|
}
|
2009-11-09 07:18:37 -08:00
|
|
|
if ((obj->cur.map != obj->prev.map) ||
|
|
|
|
(obj->cur.usemap != obj->prev.usemap))
|
2009-11-06 00:44:49 -08:00
|
|
|
{
|
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
|
|
|
goto done;
|
|
|
|
}
|
2005-01-08 02:02:18 -08:00
|
|
|
/* it's not visible - we accounted for it appearing or not so just abort */
|
|
|
|
if (!is_v) goto done;
|
|
|
|
/* clipper changed this is in addition to anything else for obj */
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
|
2005-01-08 02:02:18 -08:00
|
|
|
/* if we restacked (layer or just within a layer) and don't clip anyone */
|
|
|
|
if (obj->restack)
|
|
|
|
{
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
2005-01-08 02:02:18 -08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/* if it changed color */
|
|
|
|
if ((obj->cur.color.r != obj->prev.color.r) ||
|
|
|
|
(obj->cur.color.g != obj->prev.color.g) ||
|
|
|
|
(obj->cur.color.b != obj->prev.color.b) ||
|
|
|
|
(obj->cur.color.a != obj->prev.color.a))
|
|
|
|
{
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
2005-09-18 04:55:51 -07:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/* if it changed geometry - and obviously not visibility or color */
|
2010-09-07 20:51:24 -07:00
|
|
|
/* calculate differences since we have a constant color fill */
|
2005-09-18 04:55:51 -07:00
|
|
|
/* we really only need to update the differences */
|
|
|
|
if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
|
|
|
|
(obj->cur.geometry.y != obj->prev.geometry.y) ||
|
|
|
|
(obj->cur.geometry.w != obj->prev.geometry.w) ||
|
|
|
|
(obj->cur.geometry.h != obj->prev.geometry.h))
|
|
|
|
{
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
|
2005-01-08 02:02:18 -08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
done:
|
2009-04-15 06:40:37 -07:00
|
|
|
evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
|
2005-01-08 02:02:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
evas_object_textblock_render_post(Evas_Object *obj)
|
|
|
|
{
|
2009-06-14 13:48:37 -07:00
|
|
|
/* Evas_Object_Textblock *o; */
|
2005-01-08 02:02:18 -08:00
|
|
|
|
|
|
|
/* 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 */
|
2009-06-14 13:48:37 -07:00
|
|
|
/* o = (Evas_Object_Textblock *)(obj->object_data); */
|
2005-01-08 02:02:18 -08:00
|
|
|
/* remove those pesky changes */
|
2009-04-14 05:15:07 -07:00
|
|
|
evas_object_clip_changes_clean(obj);
|
2005-01-08 02:02:18 -08:00
|
|
|
/* move cur to prev safely for object data */
|
|
|
|
obj->prev = obj->cur;
|
2009-06-14 13:48:37 -07:00
|
|
|
/* o->prev = o->cur; */
|
2005-07-14 08:23:45 -07:00
|
|
|
/* o->changed = 0; */
|
2005-01-08 02:02:18 -08:00
|
|
|
}
|
|
|
|
|
2008-08-30 19:04:31 -07:00
|
|
|
static unsigned int evas_object_textblock_id_get(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
if (!o) return 0;
|
|
|
|
return MAGIC_OBJ_TEXTBLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj)
|
2008-08-25 22:45:04 -07:00
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
if (!o) return 0;
|
|
|
|
return MAGIC_OBJ_CUSTOM;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *evas_object_textblock_engine_data_get(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
if (!o) return NULL;
|
|
|
|
return o->engine_data;
|
|
|
|
}
|
|
|
|
|
2005-01-08 02:02:18 -08:00
|
|
|
static int
|
2010-08-18 06:56:34 -07:00
|
|
|
evas_object_textblock_is_opaque(Evas_Object *obj __UNUSED__)
|
2005-01-08 02:02:18 -08:00
|
|
|
{
|
|
|
|
/* this returns 1 if the internal object data implies that the object is */
|
|
|
|
/* currently fulyl opque over the entire gradient it occupies */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-08-18 06:56:34 -07:00
|
|
|
evas_object_textblock_was_opaque(Evas_Object *obj __UNUSED__)
|
2005-01-08 02:02:18 -08:00
|
|
|
{
|
|
|
|
/* this returns 1 if the internal object data implies that the object was */
|
|
|
|
/* currently fulyl opque over the entire gradient it occupies */
|
|
|
|
return 0;
|
|
|
|
}
|
2005-01-29 08:28:18 -08:00
|
|
|
|
|
|
|
static void
|
|
|
|
evas_object_textblock_coords_recalc(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2005-05-21 19:49:50 -07:00
|
|
|
|
2005-01-29 08:28:18 -08:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-03-30 03:31:29 -07:00
|
|
|
if ((obj->cur.geometry.w != o->last_w) ||
|
2011-03-30 03:38:02 -07:00
|
|
|
(((o->valign != 0.0) || (o->have_ellipsis)) &&
|
|
|
|
(obj->cur.geometry.h != o->last_h)))
|
2005-01-29 08:28:18 -08:00
|
|
|
{
|
2005-08-27 23:41:54 -07:00
|
|
|
o->formatted.valid = 0;
|
2005-01-29 08:28:18 -08:00
|
|
|
o->changed = 1;
|
|
|
|
}
|
|
|
|
}
|
2006-02-28 19:48:03 -08:00
|
|
|
|
2008-11-15 02:39:46 -08:00
|
|
|
static void
|
|
|
|
evas_object_textblock_scale_update(Evas_Object *obj)
|
|
|
|
{
|
2011-03-31 04:19:17 -07:00
|
|
|
Evas_Object_Textblock *o;
|
|
|
|
|
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
|
|
|
o->content_changed = 1;
|
2011-03-31 04:25:39 -07:00
|
|
|
o->formatted.valid = 0;
|
|
|
|
o->changed = 1;
|
2008-11-15 02:39:46 -08:00
|
|
|
}
|
|
|
|
|
2006-02-28 19:48:03 -08:00
|
|
|
void
|
|
|
|
_evas_object_textblock_rehint(Evas_Object *obj)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock *o;
|
2011-01-30 02:39:47 -08:00
|
|
|
Evas_Object_Textblock_Paragraph *par;
|
2008-10-17 04:23:18 -07:00
|
|
|
Evas_Object_Textblock_Line *ln;
|
|
|
|
|
2006-02-28 19:48:03 -08:00
|
|
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(o->paragraphs, par)
|
2006-02-28 19:48:03 -08:00
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(par->lines, ln)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *it;
|
2008-10-17 04:23:18 -07:00
|
|
|
|
2011-01-30 02:39:47 -08:00
|
|
|
EINA_INLIST_FOREACH(ln->items, it)
|
2011-01-30 02:31:16 -08:00
|
|
|
{
|
2011-01-30 02:39:47 -08:00
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
|
2011-01-30 02:40:47 -08:00
|
|
|
if (ti->parent.format->font.font)
|
2011-01-30 02:39:47 -08:00
|
|
|
{
|
2010-05-21 00:10:45 -07:00
|
|
|
#ifdef EVAS_FRAME_QUEUING
|
2011-01-30 02:40:47 -08:00
|
|
|
evas_common_pipe_op_text_flush(ti->parent.format->font.font);
|
2010-05-21 00:10:45 -07:00
|
|
|
#endif
|
2011-01-30 02:39:47 -08:00
|
|
|
evas_font_load_hinting_set(obj->layer->evas,
|
2011-01-30 02:40:47 -08:00
|
|
|
ti->parent.format->font.font,
|
2011-01-30 02:39:47 -08:00
|
|
|
obj->layer->evas->hinting);
|
|
|
|
}
|
2011-01-30 02:31:16 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 02:39:47 -08:00
|
|
|
}
|
2006-02-28 19:48:03 -08:00
|
|
|
}
|
2011-04-07 04:24:11 -07:00
|
|
|
_evas_textblock_changed(o, obj);
|
2011-04-07 04:24:15 -07:00
|
|
|
_evas_textblock_invalidate_all(o);
|
2006-02-28 19:48:03 -08:00
|
|
|
}
|
2010-08-10 07:36:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
|
2011-02-08 00:13:35 -08:00
|
|
|
#if 0
|
2010-08-25 07:37:52 -07:00
|
|
|
/* Good for debugging */
|
|
|
|
void
|
|
|
|
pfnode(Evas_Object_Textblock_Node_Format *n)
|
|
|
|
{
|
|
|
|
printf("Format Node: %p\n", n);
|
|
|
|
printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
|
|
|
|
printf("text_node = %p, offset = %u, visible = %d\n", n->text_node, n->offset, n->visible);
|
2011-01-30 02:31:08 -08:00
|
|
|
printf("'%s'\n", eina_strbuf_string_get(n->format));
|
2010-08-25 07:37:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ptnode(Evas_Object_Textblock_Node_Text *n)
|
|
|
|
{
|
|
|
|
printf("Text Node: %p\n", n);
|
|
|
|
printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
|
|
|
|
printf("format_node = %p\n", n->format_node);
|
2011-01-30 02:31:08 -08:00
|
|
|
printf("'%ls'\n", eina_ustrbuf_string_get(n->unicode));
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pitem(Evas_Object_Textblock_Item *it)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Text_Item *ti;
|
|
|
|
Evas_Object_Textblock_Format_Item *fi;
|
|
|
|
printf("Item: %p\n", it);
|
|
|
|
printf("Type: %s (%d)\n", (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
|
|
|
|
"TEXT" : "FORMAT", it->type);
|
|
|
|
printf("Text pos: %d Visual pos: %d\n", it->text_pos,
|
|
|
|
#ifdef BIDI_SUPPORT
|
|
|
|
it->visual_pos
|
|
|
|
#else
|
|
|
|
it->text_pos
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
printf("Coords: x = %d w = %d adv = %d\n", (int) it->x, (int) it->w,
|
|
|
|
(int) it->adv);
|
|
|
|
if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
|
|
|
|
{
|
|
|
|
ti = _ITEM_TEXT(it);
|
2011-04-13 01:36:57 -07:00
|
|
|
printf("Text: '%*ls'\n", ti->text_props.text_len, GET_ITEM_TEXT(ti));
|
2011-01-30 02:40:30 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fi = _ITEM_FORMAT(it);
|
|
|
|
printf("Format: '%s'\n", fi->item);
|
|
|
|
}
|
2010-08-25 07:37:52 -07:00
|
|
|
}
|
2011-01-30 02:40:30 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
ppar(Evas_Object_Textblock_Paragraph *par)
|
|
|
|
{
|
|
|
|
Evas_Object_Textblock_Item *it;
|
|
|
|
Eina_List *i;
|
|
|
|
EINA_LIST_FOREACH(par->logical_items, i, it)
|
|
|
|
{
|
|
|
|
printf("***********************\n");
|
|
|
|
pitem(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-25 07:37:52 -07:00
|
|
|
#endif
|
|
|
|
|