Edje calc: Fix textblock size calculation logic

Summary:
In singleline textblock, using "text.min: 1 0" and min, max width,
Edje allows to use expandable text with ellipsis. It shows ellipsis
when only text's width reach the max width.
But, Edje couldn't support same feature on multiline textblock.
Edje dose not use max height or text.max properly if ellipsis is enabled.
This feature is very useful to make a layout with dynamically aligned text.
@fix

Reviewers: cedric, tasn, woohyun, raster, herdsman

Subscribers: z-wony, eagleeye, jpeg

Differential Revision: https://phab.enlightenment.org/D3595
This commit is contained in:
Youngbok Shin 2017-02-14 16:16:45 +09:00 committed by Carsten Haitzler (Rasterman)
parent c39855a8ac
commit a6fff5bc1e
4 changed files with 329 additions and 102 deletions

View File

@ -25,9 +25,26 @@ group { name: "elm/label/base/default";
rel2.relative: 1.0 1.0;
text {
style: "label_style";
min: 0 1;
min: 1 1;
}
}
description { state: "horizontal_fixed" 0.0;
inherit: "default" 0.0;
fixed: 1 0;
text.min: 0 1;
}
}
}
programs {
program { name: "horizontal_expandable";
signal: "elm,state,horizontal,expandable"; source: "elm";
action: STATE_SET "default" 0.0;
target: "elm.text";
}
program { name: "horizontal_fixed";
signal: "elm,state,horizontal,fixed"; source: "elm";
action: STATE_SET "horizontal_fixed" 0.0;
target: "elm.text";
}
}
}

View File

@ -1445,9 +1445,17 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
int *minw, int *minh,
int *maxw, int *maxh)
{
int min_calc_w = 0, min_calc_h = 0;
if ((ep->type != EDJE_RP_TYPE_TEXT) ||
(!ep->typedata.text))
return;
/* min_calc_* values need to save calculated minumum size
* for maximum size calculation */
if (minw) min_calc_w = *minw;
if (minh) min_calc_h = *minh;
if (chosen_desc)
{
Evas_Coord tw, th, ins_l, ins_r, ins_t, ins_b;
@ -1592,56 +1600,277 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
}
if ((chosen_desc->text.min_x) || (chosen_desc->text.min_y))
{
int mw = 0, mh = 0;
evas_object_textblock_style_insets_get(ep->object, &ins_l,
&ins_r, &ins_t, &ins_b);
tw = th = 0;
if (!chosen_desc->text.min_x)
{
efl_gfx_size_set(ep->object, TO_INT(params->eval.w), TO_INT(params->eval.h));
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
/* text.min: 0 1
* text.max: X X */
int temp_h = TO_INT(params->eval.h);
int temp_w = TO_INT(params->eval.w);
if (min_calc_w > temp_w)
temp_w = min_calc_w;
if ((!chosen_desc->text.max_x) &&
maxw && (*maxw > -1) && (*maxw < temp_w))
temp_w = *maxw;
if (chosen_desc->text.max_y)
{
/* text.min: 0 1
* text.max: X 1 */
temp_h = INT_MAX / 10000;
}
else if (maxh && (*maxh > TO_INT(params->eval.h)))
{
/* text.min: 0 1
* text.max: X 0
* And there is a limit for height. */
temp_h = *maxh;
}
/* If base width for calculation is 0,
* don't get meaningless height for multiline */
if (temp_w > 0)
{
efl_gfx_size_set(ep->object, temp_w, temp_h);
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
}
else
{
efl_canvas_text_size_native_get(ep->object, NULL, &th);
th += ins_t + ins_b;
}
}
else
evas_object_textblock_size_native_get(ep->object, &tw, &th);
evas_object_textblock_style_insets_get(ep->object, &ins_l,
&ins_r, &ins_t, &ins_b);
mw = ins_l + tw + ins_r;
mh = ins_t + th + ins_b;
if (minw && chosen_desc->text.min_x)
{
if (mw > *minw) *minw = mw;
/* text.min: 1 X
* text.max: X X */
if (chosen_desc->text.min_y && (!chosen_desc->text.max_x) &&
maxw && (*maxw > -1))
{
/* text.min: 1 1
* text.max: 0 X */
int temp_w, temp_h;
temp_w = *maxw;
temp_h = INT_MAX / 10000;
if (min_calc_w > temp_w)
temp_w = min_calc_w;
if ((!chosen_desc->text.max_y) && maxh && (*maxh > -1))
{
/* text.min: 1 1
* text.max: 0 0
* There is limit for height. */
temp_h = *maxh;
}
efl_gfx_size_set(ep->object, temp_w, temp_h);
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
/* If base width for calculation is 0,
* don't get meaningless height for multiline */
if (temp_w <= 0)
{
efl_canvas_text_size_native_get(ep->object, NULL, &th);
th += ins_t + ins_b;
}
}
else
{
/* text.min: 1 X
* text.max: 1 X
* Or,
* text.min: 1 X
* text.max: 0 X without max width.
* It is a singleline Textblock. */
efl_canvas_text_size_native_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
if (!chosen_desc->text.max_x &&
(maxw && (*maxw > -1) && (*maxw < tw)))
{
/* text.min: 1 0
* text.max: 0 X */
tw = *maxw;
}
}
}
if (minh && chosen_desc->text.min_y)
if (tw > min_calc_w) min_calc_w = tw;
if (th > min_calc_h) min_calc_h = th;
if (chosen_desc->text.min_x && minw) *minw = min_calc_w;
if (chosen_desc->text.min_y && minh) *minh = min_calc_h;
}
if ((chosen_desc->text.max_x) || (chosen_desc->text.max_y))
{
evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r,
&ins_t, &ins_b);
tw = th = 0;
if (!chosen_desc->text.max_x)
{
if (mh > *minh) *minh = mh;
/* text.min: X X
* text.max: 0 1 */
int temp_w, temp_h;
if (chosen_desc->text.min_y)
{
/* text.min: X 1
* text.max: 0 1
* Already calculated in text for height. */
tw = TO_INT(params->eval.w);
if (min_calc_w > tw)
tw = min_calc_w;
th = min_calc_h;
}
else
{
/* text.min: X 0
* text.max: 0 1 */
temp_w = TO_INT(params->eval.w);
temp_h = TO_INT(params->eval.h);
if (min_calc_w > temp_w)
temp_w = min_calc_w;
if (maxw && (*maxw > -1) && (*maxw < temp_w))
temp_w = *maxw;
if (min_calc_h > temp_h)
temp_h = min_calc_h;
/* If base width for calculation is 0,
* don't get meaningless height for multiline */
if (temp_w > 0)
{
efl_gfx_size_set(ep->object, temp_w, temp_h);
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
}
else
{
efl_canvas_text_size_native_get(ep->object, NULL, &th);
th += ins_t + ins_b;
}
}
}
}
}
else
{
/* text.max: 1 X */
if (chosen_desc->text.min_x)
{
/* text.min: 1 X
* text.max: 1 X
* Singleline. */
efl_canvas_text_size_native_get(ep->object, &tw, &th);
if ((chosen_desc->text.max_x) || (chosen_desc->text.max_y))
{
int mw = 0, mh = 0;
tw += ins_l + ins_r;
th += ins_t + ins_b;
}
else
{
/* text.min: 0 X
* text.max: 1 X */
if (chosen_desc->text.max_y)
{
/* text.min: 0 X
* text.max: 1 1 */
int temp_w, temp_h;
tw = th = 0;
if (!chosen_desc->text.max_x)
{
efl_gfx_size_set(ep->object, TO_INT(params->eval.w), TO_INT(params->eval.h));
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
}
else
evas_object_textblock_size_native_get(ep->object, &tw, &th);
evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r,
&ins_t, &ins_b);
mw = ins_l + tw + ins_r;
mh = ins_t + th + ins_b;
if (maxw && chosen_desc->text.max_x)
{
if (mw > *maxw) *maxw = mw;
if (minw && (*maxw < *minw)) *maxw = *minw;
}
if (maxh && chosen_desc->text.max_y)
{
if (mh > *maxh) *maxh = mh;
if (minh && (*maxh < *minh)) *maxh = *minh;
temp_w = TO_INT(params->eval.w);
temp_h = TO_INT(params->eval.h);
if (min_calc_w > temp_w)
temp_w = min_calc_w;
if (min_calc_h > temp_h)
temp_h = min_calc_h;
if (chosen_desc->text.min_y)
{
/* text.min: 0 1
* text.max: 1 1
* There is no need to calculate it again. */
tw = min_calc_w;
th = min_calc_h;
}
else
{
/* text.min: 0 0
* text.max: 1 1 */
efl_gfx_size_set(ep->object, temp_w, temp_h);
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
/* If base width for calculation is 0,
* don't get meaningless height for multiline */
if (temp_w <= 0)
{
efl_canvas_text_size_native_get(ep->object, NULL, &th);
th += ins_t + ins_b;
}
}
}
else
{
/* text.min: 0 X
* text.max: 1 0 */
int temp_w, temp_h;
temp_w = TO_INT(params->eval.w);
if (min_calc_w > temp_w)
temp_w = min_calc_w;
efl_gfx_size_get(ep->object, NULL, &temp_h);
efl_gfx_size_set(ep->object, temp_w, temp_h);
efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
tw += ins_l + ins_r;
th += ins_t + ins_b;
/* If base width for calculation is 0,
* don't get meaningless height for multiline */
if (temp_w <= 0)
{
efl_canvas_text_size_native_get(ep->object, NULL, &th);
th += ins_t + ins_b;
}
}
}
}
if (maxw && chosen_desc->text.max_x)
{
if (tw > *maxw) *maxw = tw;
if (minw && (*maxw < *minw)) *maxw = *minw;
}
if (maxh && chosen_desc->text.max_y)
{
if (th > *maxh) *maxh = th;
if (minh && (*maxh < *minh)) *maxh = *minh;
}
}
}

View File

@ -3872,7 +3872,6 @@ _edje_object_size_min_restricted_calc(Eo *obj EINA_UNUSED, Edje *ed, Evas_Coord
Eina_Bool repeat_w, repeat_h;
Eina_Bool reset_max = EINA_TRUE;
Edje_Real_Part *pep = NULL;
Eina_Bool has_fixed_tb;
if ((!ed) || (!ed->collection))
{
@ -3916,13 +3915,11 @@ again:
}
pep = NULL;
has_fixed_tb = EINA_TRUE;
//for parts
for (i = 0; i < ed->table_parts_size; i++)
{
Edje_Real_Part *ep = ed->table_parts[i];
Evas_Coord ins_l, ins_r;
if (!ep->chosen_description) continue;
@ -3930,49 +3927,21 @@ again:
int over_w = (ep->w - ep->req.w);
int over_h = (ep->h - ep->req.h);
Eina_Bool skip_h = EINA_FALSE;
//width
if (!ep->chosen_description->fixed.w)
if ((!ep->chosen_description->fixed.w) &&
(over_w > max_over_w))
{
//We care textblock width size specially.
if (ep->part->type == EDJE_PART_TYPE_TEXTBLOCK)
{
Evas_Coord tb_mw;
evas_object_textblock_size_formatted_get(ep->object,
&tb_mw, NULL);
evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r, NULL, NULL);
tb_mw = ins_l + tb_mw + ins_r;
tb_mw -= ep->req.w;
if (tb_mw > over_w) over_w = tb_mw;
has_fixed_tb = EINA_FALSE;
}
if (over_w > max_over_w)
{
max_over_w = over_w;
repeat_w = EINA_TRUE;
pep = ep;
skip_h = EINA_TRUE;
}
max_over_w = over_w;
repeat_w = EINA_TRUE;
pep = ep;
}
//height
if (!ep->chosen_description->fixed.h)
if ((!ep->chosen_description->fixed.h) &&
(over_h > max_over_h))
{
if ((ep->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
((Edje_Part_Description_Text *)ep->chosen_description)->text.min_x ||
!skip_h)
{
if (over_h > max_over_h)
{
max_over_h = over_h;
repeat_h = EINA_TRUE;
pep = ep;
}
}
if (ep->part->type == EDJE_PART_TYPE_TEXTBLOCK)
has_fixed_tb = EINA_FALSE;
max_over_h = over_h;
repeat_h = EINA_TRUE;
pep = ep;
}
}
if (repeat_w)
@ -3992,18 +3961,14 @@ again:
if (reset_max && (calc_count > CALC_COUNT_LIMIT))
{
/* Only print it if we have a non-fixed textblock.
* We should possibly avoid all of this if in this case, but in
/* We should possibly avoid all of this if in this case, but in
* the meanwhile, just doing this. */
if (!has_fixed_tb)
{
if (pep)
ERR("file %s, group %s has a non-fixed part '%s'. Adding 'fixed: 1 1;' to source EDC may help. Continuing discarding faulty part.",
ed->path, ed->group, pep->part->name);
else
ERR("file %s, group %s runs infinite minimum calculation loops.Continuing discarding faulty parts.",
ed->path, ed->group);
}
if (pep)
ERR("file %s, group %s has a non-fixed part '%s'. Adding 'fixed: 1 1;' to source EDC may help. Continuing discarding faulty part.",
ed->path, ed->group, pep->part->name);
else
ERR("file %s, group %s runs infinite minimum calculation loops.Continuing discarding faulty parts.",
ed->path, ed->group);
reset_max = EINA_FALSE;
goto again;

View File

@ -52,18 +52,13 @@ _recalc(void *data)
resw = w;
edje_object_size_min_restricted_calc(wd->resize_obj, &minw, &minh, resw, 0);
/* This is a hack to workaround the way min size hints are treated.
* If the minimum width is smaller than the restricted width, it means
* the minimum doesn't matter. */
if ((minw <= resw) && (minw != sd->wrap_w))
{
Evas_Coord ominw = -1;
/* If wrap_w is not set, label's width has to be controlled
by outside of label. So, we don't need to set minimum width. */
if (sd->wrap_w == -1)
evas_object_size_hint_min_set(data, 0, minh);
else
evas_object_size_hint_min_set(data, minw, minh);
efl_gfx_size_hint_combined_min_get(data, &ominw, NULL);
minw = ominw;
}
evas_object_size_hint_min_set(data, minw, minh);
evas_event_thaw(evas_object_evas_get(data));
evas_event_thaw_eval(evas_object_evas_get(data));
}
@ -178,6 +173,18 @@ _label_slide_change(Evas_Object *obj)
}
}
static void
_elm_label_horizontal_size_policy_update(Eo *obj, Elm_Label_Data *sd)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
if (!sd->ellipsis && (sd->linewrap == ELM_WRAP_NONE))
edje_object_signal_emit(wd->resize_obj, "elm,state,horizontal,expandable", "elm");
else
edje_object_signal_emit(wd->resize_obj, "elm,state,horizontal,fixed", "elm");
edje_object_message_signal_process(wd->resize_obj);
}
EOLIAN static Elm_Theme_Apply
_elm_label_elm_widget_theme_apply(Eo *obj, Elm_Label_Data *sd)
{
@ -190,6 +197,8 @@ _elm_label_elm_widget_theme_apply(Eo *obj, Elm_Label_Data *sd)
int_ret = elm_obj_widget_theme_apply(efl_super(obj, MY_CLASS));
if (!int_ret) return ELM_THEME_APPLY_FAILED;
_elm_label_horizontal_size_policy_update(obj, sd);
_label_format_set(wd->resize_obj, sd->format);
_label_slide_change(obj);
@ -437,6 +446,10 @@ _elm_label_line_wrap_set(Eo *obj, Elm_Label_Data *sd, Elm_Wrap_Type wrap)
if (sd->linewrap == wrap) return;
sd->linewrap = wrap;
sd->lastw = -1;
_elm_label_horizontal_size_policy_update(obj, sd);
text = elm_layout_text_get(obj, NULL);
if (!text) return;
@ -510,6 +523,9 @@ _elm_label_ellipsis_set(Eo *obj, Elm_Label_Data *sd, Eina_Bool ellipsis)
if (sd->ellipsis == ellipsis) return;
sd->ellipsis = ellipsis;
sd->lastw = -1;
_elm_label_horizontal_size_policy_update(obj, sd);
text = elm_layout_text_get(obj, NULL);
if (!text) return;