From e3a791c4b176b7c396b1f4c56cd7a1ad54f1b745 Mon Sep 17 00:00:00 2001 From: Yeongjong Lee Date: Wed, 29 May 2019 17:24:21 +0900 Subject: efl_ui_relative_layout: allow to respect the min size of its child Summary: It will have the same policy as the Efl.Ui.Box, Table. Test Plan: elementary_test -to 'efl.ui.relative_layout' Reviewers: Jaehyun_Cho, herb Reviewed By: Jaehyun_Cho Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9029 --- src/lib/elementary/efl_ui_relative_layout.c | 78 ++++++++++++++++++++-- .../elementary/efl_ui_relative_layout_private.h | 28 ++++++++ 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/lib/elementary/efl_ui_relative_layout.c b/src/lib/elementary/efl_ui_relative_layout.c index 530179cab4..a0814cebad 100644 --- a/src/lib/elementary/efl_ui_relative_layout.c +++ b/src/lib/elementary/efl_ui_relative_layout.c @@ -177,6 +177,11 @@ _child_aspect_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1]; } //calculate min size + if (calc->aspect[1] > calc->aspect[0]) + calc->min[1] = calc->min[0] * calc->aspect[1] / calc->aspect[0]; + else + calc->min[0] = calc->min[1] * calc->aspect[0] / calc->aspect[1]; + if (calc->want[0].length < calc->min[0]) { calc->want[0].length = calc->min[0]; @@ -298,8 +303,17 @@ _child_chain_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) cur_pos += o->calc.space[axis].length; o->calc.space[axis].length -= o->calc.margin[START] + o->calc.margin[END]; o->calc.chain_state[axis] = RELATIVE_CALC_DONE; + child->calc.m0[axis] += o->calc.min[axis]; } + child->calc.mi[axis] = head->rel[START].relative * (head->calc.to[START]->calc.mj[axis] - + head->calc.to[START]->calc.mi[axis]) + head->calc.to[START]->calc.mi[axis]; + child->calc.mj[axis] = tail->rel[END].relative * (tail->calc.to[END]->calc.mj[axis] - + tail->calc.to[END]->calc.mi[axis]) + tail->calc.to[END]->calc.mi[axis]; + child->calc.m0[axis] += -child->calc.min[axis] + + (head->calc.to[START]->calc.m0[axis] * head->rel[START].relative) + + (tail->calc.to[END]->calc.m0[axis] * (1 - tail->rel[END].relative)); + return EINA_TRUE; } @@ -355,6 +369,32 @@ _child_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) (calc->space[axis].length - calc->want[axis].length) * calc->align[axis]; child->calc.state[axis] = RELATIVE_CALC_DONE; + if (child->calc.chain_state[axis] == RELATIVE_CALC_DONE) + return; + + //calculate relative layout min + calc->mi[axis] = child->rel[START].relative * (calc->to[START]->calc.mj[axis] - + calc->to[START]->calc.mi[axis]) + calc->to[START]->calc.mi[axis]; + calc->mj[axis] = child->rel[END].relative * (calc->to[END]->calc.mj[axis] - + calc->to[END]->calc.mi[axis]) + calc->to[END]->calc.mi[axis]; + calc->m0[axis] = calc->to[START]->calc.m0[axis] * child->rel[START].relative; + + if ((calc->to[START] == calc->to[END]) && + EINA_DBL_EQ(child->rel[START].relative, child->rel[END].relative)) + { + double r, a; // relative, align + r = calc->mi[axis] + + (child->rel[START].relative * (calc->mj[axis] - calc->mi[axis])); + a = calc->align[axis]; + calc->m0[axis] += (calc->min[axis] + calc->margin[START] + calc->margin[END]) * + ((EINA_DBL_EQ(r, 0.0) || (!EINA_DBL_EQ(r, 1.0) && (a < r))) ? + ((1 - a) / (1 - r)) : (a / r)); + } + else + { + calc->m0[axis] += calc->to[END]->calc.m0[axis] * (1 - child->rel[END].relative); + } + } static void @@ -386,18 +426,36 @@ _hash_clear_cb(void *data) static Eina_Bool _hash_child_calc_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, - void *data, void *fdata EINA_UNUSED) + void *data, void *fdata) { Efl_Ui_Relative_Layout_Child *child = data; + Efl_Ui_Relative_Layout_Calc *calc = &(child->calc); + Efl_Ui_Relative_Layout_Data *pd = fdata; Eina_Rect want; + int axis, layout_min; + double min_len; _child_calc(child, 0); _child_calc(child, 1); - want.x = child->calc.want[0].position; - want.w = child->calc.want[0].length; - want.y = child->calc.want[1].position; - want.h = child->calc.want[1].length; + want.x = calc->want[0].position; + want.w = calc->want[0].length; + want.y = calc->want[1].position; + want.h = calc->want[1].length; + + for (axis = 0; axis < 2; axis++) + { + layout_min = 0; + min_len = calc->mj[axis] - calc->mi[axis]; + if (EINA_DBL_EQ(min_len, 0.0)) + layout_min = calc->m0[axis]; + else + layout_min = ((calc->min[axis] + calc->margin[START] + + calc->margin[END] + calc->m0[axis]) / fabs(min_len)) + 0.5; + + if (pd->base->calc.min[axis] < layout_min) + pd->base->calc.min[axis] = layout_min; + } efl_gfx_entity_geometry_set(child->obj, want); return EINA_TRUE; @@ -437,6 +495,8 @@ _hash_child_init_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key E calc->max[1] = max.h; calc->min[0] = min.w; calc->min[1] = min.h; + calc->m0[0] = 0.0; + calc->m0[1] = 0.0; calc->want[0].position = 0; calc->want[0].length = 0; @@ -477,9 +537,13 @@ _efl_ui_relative_layout_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Relative_L pd->base->calc.want[0].length = want.w; pd->base->calc.want[1].position = want.y; pd->base->calc.want[1].length = want.h; + pd->base->calc.min[0] = 0; + pd->base->calc.min[1] = 0; eina_hash_foreach(pd->children, _hash_child_init_foreach_cb, pd); - eina_hash_foreach(pd->children, _hash_child_calc_foreach_cb, NULL); + eina_hash_foreach(pd->children, _hash_child_calc_foreach_cb, pd); + + efl_gfx_hint_size_restricted_min_set(obj, EINA_SIZE2D(pd->base->calc.min[0], pd->base->calc.min[1])); efl_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL); } @@ -550,6 +614,8 @@ _efl_ui_relative_layout_efl_object_constructor(Eo *obj, Efl_Ui_Relative_Layout_D pd->base->rel[TOP].relative = 0.0; pd->base->rel[BOTTOM].to = obj; pd->base->rel[BOTTOM].relative = 1.0; + pd->base->calc.mi[0] = pd->base->calc.mi[1] = 0.0; + pd->base->calc.mj[0] = pd->base->calc.mj[1] = 1.0; pd->base->calc.state[0] = RELATIVE_CALC_DONE; pd->base->calc.state[1] = RELATIVE_CALC_DONE; pd->base->calc.chain_state[0] = RELATIVE_CALC_DONE; diff --git a/src/lib/elementary/efl_ui_relative_layout_private.h b/src/lib/elementary/efl_ui_relative_layout_private.h index 2aa150a333..79a22bed1d 100644 --- a/src/lib/elementary/efl_ui_relative_layout_private.h +++ b/src/lib/elementary/efl_ui_relative_layout_private.h @@ -36,6 +36,34 @@ struct _Efl_Ui_Relative_Layout_Calc double weight[2]; double align[2]; double comp_factor; + /* m0 is static min size which is added to the other children min size. + * only if both (target, relative)[0] and (target, relative)[1] are same, + * it has non-zero value. it is calculated as (min * (align / relative)) if + * align is greater than relative, (min * ((1 - align) / (1 - relative))) otherwise. + * mi, mj are transformed relative based on layout min size. they are + * calculated as (target.mi + (relative * (target.mj - target.mi))). for example, + * there are two children of relative_layout that has different target base. + * | | obj1 | obj2 | + * | min | 100 | 100 | + * |left.target | layout| obj1 | + * |left.relative | 0.0 | 0.5 | + * |right.target | layout| obj1 | + * |right.relative| 0.5 | 1.0 | + * | mi | 0.0 | 0.25 | + * | mj | 0.5 | 0.5 | + * + * obj1.mi = layout.mi(0.0) + (obj1.relative(0.0) * (layout.mj(1.0) - layout.mi(0.0))) = 0.0 + * obj1.mj = layout.mi(0.0) + (obj1.relative(0.5) * (layout.mj(1.0) - layout.mi(0.0))) = 0.5 + * obj2.mi = obj1.mi(0.0) + (obj2.relative(0.5) * (obj1.mj(0.5) - obj1.mi(0.0))) = 0.25 + * obj2.mj = obj1.mi(0.0) + (obj2.relative(1.0) * (obj1.mj(0.5) - obj1.mi(0.0))) = 0.5 + * layout min size is calculated as maximum of (child_min + m0) / (mj - mi). + * in the example, obj1 require layout min size as + * ((child_min(100) + m0(0)) / (mj(0.5) - mi(0.0))) = 200. obj2 require + * layout min size as ((100 + 0) / (0.5 - 0.25)) = 400. as a result, layout + * min size is max(200, 400) = 400. + */ + double m0[2]; + double mi[2], mj[2]; struct { int position; -- cgit v1.2.1