From a6fff5bc1e5e30a946e435369bcbaa406dd5d5ba Mon Sep 17 00:00:00 2001 From: Youngbok Shin Date: Tue, 14 Feb 2017 16:16:45 +0900 Subject: [PATCH] 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 --- data/elementary/themes/edc/elm/label.edc | 19 +- src/lib/edje/edje_calc.c | 305 ++++++++++++++++++++--- src/lib/edje/edje_util.c | 69 ++--- src/lib/elementary/elm_label.c | 38 ++- 4 files changed, 329 insertions(+), 102 deletions(-) diff --git a/data/elementary/themes/edc/elm/label.edc b/data/elementary/themes/edc/elm/label.edc index b1e273bc09..99227d8067 100644 --- a/data/elementary/themes/edc/elm/label.edc +++ b/data/elementary/themes/edc/elm/label.edc @@ -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"; } } } diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index 320fbffc89..d52069d85c 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -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; + } } } diff --git a/src/lib/edje/edje_util.c b/src/lib/edje/edje_util.c index d8a29fe369..158259eaf0 100644 --- a/src/lib/edje/edje_util.c +++ b/src/lib/edje/edje_util.c @@ -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; diff --git a/src/lib/elementary/elm_label.c b/src/lib/elementary/elm_label.c index 7af1237278..76cb63c22c 100644 --- a/src/lib/elementary/elm_label.c +++ b/src/lib/elementary/elm_label.c @@ -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;