EINA_INLIST;
Evas_Object_Textblock_Item *items;
Evas_Object_Textblock_Paragraph *par;
+ Evas_Object_Textblock_Text_Item *ellip_ti;
int x, y, w, h;
int baseline;
int line_no;
int linegap;
double linerelgap;
double linefill;
+ double ellipsis;
unsigned char style;
unsigned char wrap_word : 1;
unsigned char wrap_char : 1;
* @param ln the layout line to be freed, must not be NULL.
*/
static void
-_line_free(const Evas_Object *obj __UNUSED__, Evas_Object_Textblock_Line *ln)
+_line_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln)
{
- /* Items are freed from the logical list */
+ /* Items are freed from the logical list, except for the ellip item */
+ if (ln->ellip_ti) _item_free(obj, NULL, _ITEM(ln->ellip_ti));
if (ln) free(ln);
}
static const char *linerelgapstr = NULL;
static const char *itemstr = NULL;
static const char *linefillstr = NULL;
+static const char *ellipsisstr = NULL;
/**
* @internal
linerelgapstr = eina_stringshare_add("linerelgap");
itemstr = eina_stringshare_add("item");
linefillstr = eina_stringshare_add("linefill");
+ ellipsisstr = eina_stringshare_add("ellipsis");
}
format_refcount++;
}
eina_stringshare_del(linerelgapstr);
eina_stringshare_del(itemstr);
eina_stringshare_del(linefillstr);
+ eina_stringshare_del(ellipsisstr);
}
/**
}
}
}
+ 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;
+ }
if (new_font)
{
Eina_Bool align_auto;
};
-static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Text_Item *ti, const Evas_Object_Textblock_Item *rel);
+static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, const Evas_Object_Textblock_Item *rel);
/**
* @internal
* Adjust the ascent/descent of the format and context.
/**
* @internal
- * Reorder the items in a line.
+ * Reorder the items in visual order
*
* @param line the line to reorder
*/
evas_common_text_props_split(&ti->parent.text_props,
&new_ti->parent.text_props, cut2);
- _layout_text_add_logical_item(c, ti->parent.format, new_ti, _ITEM(ti));
+ _layout_text_add_logical_item(c, new_ti, _ITEM(ti));
/* FIXME: Will break with kerning and a bunch of other stuff, should
* maybe adjust the last adv of the prev and the offset of the cur
evas_common_text_props_split(&ti->parent.text_props,
&white_ti->parent.text_props, cut);
- _layout_text_add_logical_item(c, ti->parent.format, white_ti, _ITEM(ti));
+ _layout_text_add_logical_item(c, white_ti, _ITEM(ti));
ti->parent.w -= white_ti->parent.w;
ti->parent.adv -= white_ti->parent.adv;
}
/**
* @internal
- * Adds the item to the list, updates the item's properties (e.g, x,w,h)
+ * Calculates an item's size.
*
* @param c the context
- * @param fmt the format of the item.
* @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_Format *fmt,
- Evas_Object_Textblock_Text_Item *ti,
- const Evas_Object_Textblock_Item *rel)
+_text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti)
{
int tw, th, adv, inset;
+ const Evas_Object_Textblock_Format *fmt = ti->parent.format;
tw = th = 0;
if (fmt->font.font)
ti->text, &ti->parent.text_props);
ti->parent.adv = adv;
ti->parent.x = 0;
+}
+
+/**
+ * @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,
+ const Evas_Object_Textblock_Item *rel)
+{
+ _text_item_update_sizes(c, ti);
+
c->par->logical_items = eina_list_append_relative(
c->par->logical_items, ti, rel);
}
}
str += tmp_len;
- _layout_text_add_logical_item(c, fmt, ti, NULL);
+ _layout_text_add_logical_item(c, ti, NULL);
/* Break if we reached the end. */
if (!*str)
return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_TRUE);
}
-static void
+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;
+ const Eina_Unicode _ellip_str[4] = { '.', '.', '.', '\0' };
+ /* We assume that the format stack has at least one time,
+ * the only reason it may not have, is more </> than <>, other
+ * than that, we're safe. The last item is the base format. */
+ ellip_ti = _layout_text_item_new(c,
+ eina_list_data_get(eina_list_last(c->format_stack)),
+ _ellip_str);
+ ellip_ti->parent.text_node = cur_it->text_node;
+ ellip_ti->parent.text_pos = cur_it->text_pos;
+ if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
+ {
+ ellip_ti->parent.text_pos += eina_unicode_strlen(ellip_ti->text);
+ }
+ else
+ {
+ ellip_ti->parent.text_pos++;
+ }
+
+ evas_common_text_props_bidi_set(&ellip_ti->parent.text_props,
+ ellip_ti->parent.text_node->bidi_props, ellip_ti->parent.text_pos);
+ evas_common_text_props_script_set (&ellip_ti->parent.text_props,
+ ellip_ti->text);
+ c->ENFN->font_shape(c->ENDT, ellip_ti->parent.format->font.font,
+ ellip_ti->text, &ellip_ti->parent.text_props,
+ ellip_ti->parent.text_node->bidi_props,
+ ellip_ti->parent.text_pos, eina_unicode_strlen(_ellip_str));
+ _text_item_update_sizes(c, ellip_ti);
+
+ 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
_layout_visualize_par(Ctxt *c)
{
Evas_Object_Textblock_Item *it;
Eina_List *i;
if (!c->par->logical_items)
- return;
+ return 2;
it = _ITEM(eina_list_data_get(c->par->logical_items));
_layout_line_new(c, it->format);
/* Check if we need to wrap, i.e the text is bigger than the width */
if ((c->w >= 0) &&
- ((it->format->wrap_word) || (it->format->wrap_char) ||
- it->format->wrap_mixed) &&
((c->x + it->adv) >
(c->w - c->o->style_pad.l - c->o->style_pad.r -
c->marginl - c->marginr)))
{
- if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
+ /* 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))
{
- /* Don't wrap if it's the only item */
- if (c->ln->items)
+ 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
{
- /*FIXME: I should handle tabs correctly, i.e like
- * spaces */
- _layout_line_advance(c, it->format);
+ wrap = _layout_text_cutoff_get(c, last_it->format,
+ last_ti);
+ if ((wrap > 0) && last_ti->text[wrap])
+ {
+ _layout_item_text_split_strip_white(c, last_ti,
+ 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;
+ }
+ }
}
+ 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);
+
+ return 1;
}
- else
+ else if (it->format->wrap_word || it->format->wrap_char ||
+ it->format->wrap_mixed)
{
- Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
- int wrap;
-
- adv_line = 1;
- if (it->format->wrap_word)
- wrap = _layout_get_wordwrap(c, it->format, ti);
- else if (it->format->wrap_char)
- wrap = _layout_get_charwrap(c, it->format, ti);
- else if (it->format->wrap_mixed)
- wrap = _layout_get_mixedwrap(c, it->format, ti);
- else
- wrap = -1;
-
- if (wrap > 0)
+ if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
{
- _layout_item_text_split_strip_white(c, ti, wrap);
+ /* 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);
+ }
}
- else if (wrap == 0)
+ else
{
- /* Should wrap before the item */
- adv_line = 0;
- redo_item = 1;
- _layout_line_advance(c, it->format);
+ Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
+ int wrap;
+
+ adv_line = 1;
+ if (it->format->wrap_word)
+ wrap = _layout_get_wordwrap(c, it->format, ti);
+ else if (it->format->wrap_char)
+ wrap = _layout_get_charwrap(c, it->format, ti);
+ else if (it->format->wrap_mixed)
+ wrap = _layout_get_mixedwrap(c, it->format, ti);
+ else
+ wrap = -1;
+
+ if (wrap > 0)
+ {
+ _layout_item_text_split_strip_white(c, ti, wrap);
+ }
+ else if (wrap == 0)
+ {
+ /* Should wrap before the item */
+ adv_line = 0;
+ redo_item = 1;
+ _layout_line_advance(c, it->format);
+ }
}
}
}
/* Here 'it' is the last format used */
_layout_line_finalize(c, it->format);
}
+ return 0;
}
/**
{
c->par = par;
_layout_update_par(c);
- _layout_visualize_par(c);
+ /* Break if we should stop here. */
+ if (_layout_visualize_par(c))
+ break;
}
}
/* End of visual layout creation */