1 #ifndef EFL_UI_RELATIVE_CONTAINER_PRIVATE_H
2 #define EFL_UI_RELATIVE_CONTAINER_PRIVATE_H
3 
4 #ifdef HAVE_CONFIG_H
5 # include "elementary_config.h"
6 #endif
7 
8 #define EFL_PACK_LAYOUT_PROTECTED
9 
10 #include <Elementary.h>
11 #include "elm_priv.h"
12 
13 typedef enum _Efl_Ui_Relative_Container_Calc_State
14 {
15    RELATIVE_CALC_NONE,
16    RELATIVE_CALC_DONE,
17    RELATIVE_CALC_ON
18 } Efl_Ui_Relative_Container_Calc_State;
19 
20 typedef struct _Efl_Ui_Relative_Container_Data        Efl_Ui_Relative_Container_Data;
21 typedef struct _Efl_Ui_Relative_Container_Child       Efl_Ui_Relative_Container_Child;
22 typedef struct _Efl_Ui_Relative_Container_Calc        Efl_Ui_Relative_Container_Calc;
23 typedef struct _Efl_Ui_Relative_Container_Relation    Efl_Ui_Relative_Container_Relation;
24 typedef struct _Efl_Ui_Relative_Container_Content_Iterator Efl_Ui_Relative_Container_Content_Iterator;
25 
26 struct _Efl_Ui_Relative_Container_Calc
27 {
28    EINA_INLIST;
29 
30    int                                max[2];
31    int                                min[2];
32    int                                aspect[2];
33    int                                margin[4];
34    Efl_Gfx_Hint_Aspect                aspect_type;
35    Eina_Bool                          fill[2];
36    double                             weight[2];
37    double                             align[2];
38    double                             comp_factor;
39    /*  m0 is static min size which is added to the other children min size.
40     * only if both (target, relative)[0] and (target, relative)[1] are same,
41     * it has non-zero value. it is calculated as (min * (align / relative)) if
42     * align is greater than relative, (min * ((1 - align) / (1 - relative))) otherwise.
43     *  mi, mj are transformed relative based on layout min size. they are
44     * calculated as (target.mi + (relative * (target.mj - target.mi))). for example,
45     * there are two children of relative_container that has different target base.
46     *  |              | obj1  | obj2 |
47     *  |      min     | 100   | 100  |
48     *  |left.target   | layout| obj1 |
49     *  |left.relative | 0.0   | 0.5  |
50     *  |right.target  | layout| obj1 |
51     *  |right.relative| 0.5   | 1.0  |
52     *  |      mi      | 0.0   | 0.25 |
53     *  |      mj      | 0.5   | 0.5  |
54     *
55     * obj1.mi = layout.mi(0.0) + (obj1.relative(0.0) * (LAyout.mj(1.0) - layout.mi(0.0))) = 0.0
56     * obj1.mj = layout.mi(0.0) + (obj1.relative(0.5) * (layout.mj(1.0) - layout.mi(0.0))) = 0.5
57     * obj2.mi = obj1.mi(0.0) + (obj2.relative(0.5) * (obj1.mj(0.5) - obj1.mi(0.0))) = 0.25
58     * obj2.mj = obj1.mi(0.0) + (obj2.relative(1.0) * (obj1.mj(0.5) - obj1.mi(0.0))) = 0.5
59     *  layout min size is calculated as maximum of (child_min + m0) / (mj - mi).
60     * in the example, obj1 require layout min size as
61     * ((child_min(100) + m0(0)) / (mj(0.5) - mi(0.0))) = 200. obj2 require
62     * layout min size as ((100 + 0) / (0.5 - 0.25)) = 400. as a result, layout
63     * min size is max(200, 400) = 400.
64     */
65    double                             m0[2];
66    double                             mi[2], mj[2];
67 
68    struct {
69       int position;
70       double length;
71    } space[2], want[2];
72 
73    Efl_Ui_Relative_Container_Calc_State  state[2];
74    Efl_Ui_Relative_Container_Calc_State  chain_state[2];
75    Efl_Ui_Relative_Container_Child      *to[4];
76 };
77 
78 struct _Efl_Ui_Relative_Container_Data
79 {
80    Eo        *obj;
81    Eo        *clipper;
82    Eina_Hash *children;
83    Efl_Ui_Relative_Container_Child *base;
84 };
85 
86 struct _Efl_Ui_Relative_Container_Relation
87 {
88    Efl_Object *to;
89    double relative_position;
90 };
91 
92 struct _Efl_Ui_Relative_Container_Child
93 {
94    Eo                               *obj;
95    Eo                               *layout;
96    Efl_Ui_Relative_Container_Relation   rel[4];
97    Efl_Ui_Relative_Container_Calc       calc;
98 };
99 
100 struct _Efl_Ui_Relative_Container_Content_Iterator
101 {
102    Eina_Iterator  iterator;
103    Eina_Iterator *real_iterator;
104    Eo            *relative_container;
105 };
106 
107 #define EFL_UI_RELATIVE_CONTAINER_RELATION_SET_GET(direction, DIRECTION) \
108    EOLIAN static void \
109    _efl_ui_relative_container_relation_ ## direction ## _set(Eo *obj, Efl_Ui_Relative_Container_Data *pd, Eo *child, Eo *target, double relative_position) \
110    { \
111       Efl_Ui_Relative_Container_Child *rc; \
112       if (!child) return; \
113       rc = _relative_child_get(pd, child); \
114       if (!rc) return; \
115       if (target) rc->rel[DIRECTION].to = target; \
116       if (relative_position < 0) relative_position = 0; \
117       else if (relative_position > 1) relative_position = 1; \
118       rc->rel[DIRECTION].relative_position = relative_position; \
119       efl_pack_layout_request(obj); \
120    } \
121    \
122    EOLIAN static void \
123    _efl_ui_relative_container_relation_ ## direction ## _get(const Eo *obj EINA_UNUSED, Efl_Ui_Relative_Container_Data *pd, Eo *child, Eo **target, double *relative_position) \
124    { \
125       Efl_Ui_Relative_Container_Child *rc; \
126       Eo *rel_to = NULL; \
127       double rel_relative = 0.0; \
128       rc = eina_hash_find(pd->children, &child); \
129       if (rc) \
130         { \
131            rel_to = rc->rel[DIRECTION].to; \
132            rel_relative = rc->rel[DIRECTION].relative_position; \
133         } \
134       else \
135         ERR("child(%p(%s)) is not registered", child, efl_class_name_get(child)); \
136       if (target) *target = rel_to; \
137       if (relative_position) *relative_position = rel_relative; \
138    }
139 
140 #endif
141