1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "layout/flex_layout.h"
17a3e0fd82Sopenharmony_ci
18a3e0fd82Sopenharmony_cinamespace OHOS {
19a3e0fd82Sopenharmony_civoid FlexLayout::LayoutChildren(bool needInvalidate)
20a3e0fd82Sopenharmony_ci{
21a3e0fd82Sopenharmony_ci    if (childrenHead_ == nullptr) {
22a3e0fd82Sopenharmony_ci        return;
23a3e0fd82Sopenharmony_ci    }
24a3e0fd82Sopenharmony_ci
25a3e0fd82Sopenharmony_ci    if ((direction_ == LAYOUT_HOR) || (direction_ == LAYOUT_HOR_R)) {
26a3e0fd82Sopenharmony_ci        LayoutHorizontal();
27a3e0fd82Sopenharmony_ci    } else {
28a3e0fd82Sopenharmony_ci        LayoutVertical();
29a3e0fd82Sopenharmony_ci    }
30a3e0fd82Sopenharmony_ci    if (needInvalidate) {
31a3e0fd82Sopenharmony_ci        Invalidate();
32a3e0fd82Sopenharmony_ci    }
33a3e0fd82Sopenharmony_ci}
34a3e0fd82Sopenharmony_ci
35a3e0fd82Sopenharmony_civoid FlexLayout::GetStartPos(const int16_t& length,
36a3e0fd82Sopenharmony_ci                             int16_t& pos,
37a3e0fd82Sopenharmony_ci                             int16_t& interval,
38a3e0fd82Sopenharmony_ci                             int16_t count,
39a3e0fd82Sopenharmony_ci                             uint16_t* validLengths,
40a3e0fd82Sopenharmony_ci                             uint16_t* childsNum)
41a3e0fd82Sopenharmony_ci{
42a3e0fd82Sopenharmony_ci    if (!validLengths || !childsNum) {
43a3e0fd82Sopenharmony_ci        return;
44a3e0fd82Sopenharmony_ci    }
45a3e0fd82Sopenharmony_ci    pos = 0;
46a3e0fd82Sopenharmony_ci    interval = 0;
47a3e0fd82Sopenharmony_ci
48a3e0fd82Sopenharmony_ci    if (majorAlign_ == ALIGN_START) {
49a3e0fd82Sopenharmony_ci        pos = 0;
50a3e0fd82Sopenharmony_ci    } else if (majorAlign_ == ALIGN_END) {
51a3e0fd82Sopenharmony_ci        pos = length - validLengths[count];
52a3e0fd82Sopenharmony_ci        /* if total length of children is too long or only one child, layout them centerly no matter what key word set.
53a3e0fd82Sopenharmony_ci         */
54a3e0fd82Sopenharmony_ci    } else if ((majorAlign_ == ALIGN_CENTER) || (validLengths[count] >= length) || (childsNum[count] == 1)) {
55a3e0fd82Sopenharmony_ci        pos = (length - validLengths[count]) / 2; // 2: half
56a3e0fd82Sopenharmony_ci    } else if (majorAlign_ == ALIGN_AROUND) {
57a3e0fd82Sopenharmony_ci        if (childsNum[count] == 0) {
58a3e0fd82Sopenharmony_ci            return;
59a3e0fd82Sopenharmony_ci        }
60a3e0fd82Sopenharmony_ci        interval = (length - validLengths[count]) / childsNum[count];
61a3e0fd82Sopenharmony_ci        pos = interval / 2; // 2: half
62a3e0fd82Sopenharmony_ci    } else if (majorAlign_ == ALIGN_EVENLY) {
63a3e0fd82Sopenharmony_ci        interval = (length - validLengths[count]) / (childsNum[count] + 1);
64a3e0fd82Sopenharmony_ci        pos = interval;
65a3e0fd82Sopenharmony_ci    } else {
66a3e0fd82Sopenharmony_ci        interval = (length - validLengths[count]) / (childsNum[count] - 1);
67a3e0fd82Sopenharmony_ci        pos = 0;
68a3e0fd82Sopenharmony_ci    }
69a3e0fd82Sopenharmony_ci}
70a3e0fd82Sopenharmony_ci
71a3e0fd82Sopenharmony_civoid FlexLayout::GetNoWrapStartPos(const int16_t& length, int16_t& majorPos, int16_t& interval)
72a3e0fd82Sopenharmony_ci{
73a3e0fd82Sopenharmony_ci    uint16_t childrenNum = 0;
74a3e0fd82Sopenharmony_ci    uint16_t totalValidLength = 0;
75a3e0fd82Sopenharmony_ci
76a3e0fd82Sopenharmony_ci    CalValidLength(totalValidLength, childrenNum);
77a3e0fd82Sopenharmony_ci    GetStartPos(length, majorPos, interval, 0, &totalValidLength, &childrenNum);
78a3e0fd82Sopenharmony_ci}
79a3e0fd82Sopenharmony_ci
80a3e0fd82Sopenharmony_civoid FlexLayout::GetRowStartPos(int16_t& pos,
81a3e0fd82Sopenharmony_ci                                int16_t& interval,
82a3e0fd82Sopenharmony_ci                                int16_t count,
83a3e0fd82Sopenharmony_ci                                uint16_t* rowsWidth,
84a3e0fd82Sopenharmony_ci                                uint16_t* rowsChildNum)
85a3e0fd82Sopenharmony_ci{
86a3e0fd82Sopenharmony_ci    GetStartPos(GetWidth(), pos, interval, count, rowsWidth, rowsChildNum);
87a3e0fd82Sopenharmony_ci}
88a3e0fd82Sopenharmony_ci
89a3e0fd82Sopenharmony_civoid FlexLayout::GetColumnStartPos(int16_t& pos,
90a3e0fd82Sopenharmony_ci                                   int16_t& interval,
91a3e0fd82Sopenharmony_ci                                   int16_t count,
92a3e0fd82Sopenharmony_ci                                   uint16_t* columnsHeight,
93a3e0fd82Sopenharmony_ci                                   uint16_t* columnsChildNum)
94a3e0fd82Sopenharmony_ci{
95a3e0fd82Sopenharmony_ci    GetStartPos(GetHeight(), pos, interval, count, columnsHeight, columnsChildNum);
96a3e0fd82Sopenharmony_ci}
97a3e0fd82Sopenharmony_ci
98a3e0fd82Sopenharmony_civoid FlexLayout::CalValidLength(uint16_t& totalValidLength, uint16_t& allChildNum)
99a3e0fd82Sopenharmony_ci{
100a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
101a3e0fd82Sopenharmony_ci    int16_t left;
102a3e0fd82Sopenharmony_ci    int16_t right;
103a3e0fd82Sopenharmony_ci    int16_t top;
104a3e0fd82Sopenharmony_ci    int16_t bottom;
105a3e0fd82Sopenharmony_ci
106a3e0fd82Sopenharmony_ci    /* calculate valid length of all children views */
107a3e0fd82Sopenharmony_ci    while (child != nullptr) {
108a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
109a3e0fd82Sopenharmony_ci            child->ReMeasure();
110a3e0fd82Sopenharmony_ci            if ((direction_ == LAYOUT_HOR) || (direction_ == LAYOUT_HOR_R)) {
111a3e0fd82Sopenharmony_ci                left = child->GetStyle(STYLE_MARGIN_LEFT);
112a3e0fd82Sopenharmony_ci                right = child->GetStyle(STYLE_MARGIN_RIGHT);
113a3e0fd82Sopenharmony_ci                totalValidLength += (child->GetRelativeRect().GetWidth() + left + right);
114a3e0fd82Sopenharmony_ci            } else {
115a3e0fd82Sopenharmony_ci                top = child->GetStyle(STYLE_MARGIN_TOP);
116a3e0fd82Sopenharmony_ci                bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
117a3e0fd82Sopenharmony_ci                totalValidLength += (child->GetRelativeRect().GetHeight() + top + bottom);
118a3e0fd82Sopenharmony_ci            }
119a3e0fd82Sopenharmony_ci            allChildNum++;
120a3e0fd82Sopenharmony_ci        }
121a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
122a3e0fd82Sopenharmony_ci    }
123a3e0fd82Sopenharmony_ci}
124a3e0fd82Sopenharmony_ci
125a3e0fd82Sopenharmony_civoid FlexLayout::CalRowCount()
126a3e0fd82Sopenharmony_ci{
127a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
128a3e0fd82Sopenharmony_ci    int16_t pos = 0;
129a3e0fd82Sopenharmony_ci    int16_t left;
130a3e0fd82Sopenharmony_ci    int16_t right;
131a3e0fd82Sopenharmony_ci
132a3e0fd82Sopenharmony_ci    rowCount_ = 1;
133a3e0fd82Sopenharmony_ci    while (child != nullptr) {
134a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
135a3e0fd82Sopenharmony_ci            child->ReMeasure();
136a3e0fd82Sopenharmony_ci            left = child->GetStyle(STYLE_MARGIN_LEFT);
137a3e0fd82Sopenharmony_ci            right = child->GetStyle(STYLE_MARGIN_RIGHT);
138a3e0fd82Sopenharmony_ci            pos += left;
139a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetWidth() + right) > GetWidth()) {
140a3e0fd82Sopenharmony_ci                pos = left;
141a3e0fd82Sopenharmony_ci                rowCount_++;
142a3e0fd82Sopenharmony_ci            }
143a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetWidth() + right;
144a3e0fd82Sopenharmony_ci        }
145a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
146a3e0fd82Sopenharmony_ci    }
147a3e0fd82Sopenharmony_ci}
148a3e0fd82Sopenharmony_ci
149a3e0fd82Sopenharmony_civoid FlexLayout::GetRowMaxHeight(uint16_t size, uint16_t* maxRosHegiht)
150a3e0fd82Sopenharmony_ci{
151a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
152a3e0fd82Sopenharmony_ci    int16_t pos = 0;
153a3e0fd82Sopenharmony_ci    int16_t left;
154a3e0fd82Sopenharmony_ci    int16_t right;
155a3e0fd82Sopenharmony_ci    int16_t top;
156a3e0fd82Sopenharmony_ci    int16_t bottom;
157a3e0fd82Sopenharmony_ci    uint16_t i = 0;
158a3e0fd82Sopenharmony_ci    uint16_t height = 0;
159a3e0fd82Sopenharmony_ci
160a3e0fd82Sopenharmony_ci    if ((maxRosHegiht == nullptr) || (size > rowCount_)) {
161a3e0fd82Sopenharmony_ci        return;
162a3e0fd82Sopenharmony_ci    }
163a3e0fd82Sopenharmony_ci
164a3e0fd82Sopenharmony_ci    while (child != nullptr) {
165a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
166a3e0fd82Sopenharmony_ci            left = child->GetStyle(STYLE_MARGIN_LEFT);
167a3e0fd82Sopenharmony_ci            right = child->GetStyle(STYLE_MARGIN_RIGHT);
168a3e0fd82Sopenharmony_ci            top = child->GetStyle(STYLE_MARGIN_TOP);
169a3e0fd82Sopenharmony_ci            bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
170a3e0fd82Sopenharmony_ci            pos += left;
171a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetWidth() + right) > GetWidth()) {
172a3e0fd82Sopenharmony_ci                pos = left;
173a3e0fd82Sopenharmony_ci                maxRosHegiht[i] = height;
174a3e0fd82Sopenharmony_ci                height = 0;
175a3e0fd82Sopenharmony_ci                i++;
176a3e0fd82Sopenharmony_ci            }
177a3e0fd82Sopenharmony_ci            height = MATH_MAX(height, child->GetRelativeRect().GetHeight() + top + bottom);
178a3e0fd82Sopenharmony_ci            maxRosHegiht[i] = height;
179a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetWidth() + right;
180a3e0fd82Sopenharmony_ci        }
181a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
182a3e0fd82Sopenharmony_ci    }
183a3e0fd82Sopenharmony_ci}
184a3e0fd82Sopenharmony_ci
185a3e0fd82Sopenharmony_civoid FlexLayout::GetRowsWidth(uint16_t rowNum, uint16_t* rowsWidth, uint16_t* rowsChildNum)
186a3e0fd82Sopenharmony_ci{
187a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
188a3e0fd82Sopenharmony_ci    int16_t pos = 0;
189a3e0fd82Sopenharmony_ci    int16_t left;
190a3e0fd82Sopenharmony_ci    int16_t right;
191a3e0fd82Sopenharmony_ci    uint16_t rowChildNum = 0;
192a3e0fd82Sopenharmony_ci    uint16_t rowCount = 0;
193a3e0fd82Sopenharmony_ci    uint16_t width = 0;
194a3e0fd82Sopenharmony_ci
195a3e0fd82Sopenharmony_ci    if ((rowsWidth == nullptr) || (rowsChildNum == nullptr) || (rowNum > rowCount_)) {
196a3e0fd82Sopenharmony_ci        return;
197a3e0fd82Sopenharmony_ci    }
198a3e0fd82Sopenharmony_ci
199a3e0fd82Sopenharmony_ci    while (child != nullptr) {
200a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
201a3e0fd82Sopenharmony_ci            left = child->GetStyle(STYLE_MARGIN_LEFT);
202a3e0fd82Sopenharmony_ci            right = child->GetStyle(STYLE_MARGIN_RIGHT);
203a3e0fd82Sopenharmony_ci            pos += left;
204a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetWidth() + right) > GetWidth()) {
205a3e0fd82Sopenharmony_ci                pos = left;
206a3e0fd82Sopenharmony_ci                rowsWidth[rowCount] = width;
207a3e0fd82Sopenharmony_ci                width = 0;
208a3e0fd82Sopenharmony_ci                rowsChildNum[rowCount] = rowChildNum;
209a3e0fd82Sopenharmony_ci                rowChildNum = 0;
210a3e0fd82Sopenharmony_ci                rowCount++;
211a3e0fd82Sopenharmony_ci            }
212a3e0fd82Sopenharmony_ci            width += child->GetRelativeRect().GetWidth() + right + left;
213a3e0fd82Sopenharmony_ci            rowsWidth[rowCount] = width;
214a3e0fd82Sopenharmony_ci            rowChildNum++;
215a3e0fd82Sopenharmony_ci            rowsChildNum[rowCount] = rowChildNum;
216a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetWidth() + right;
217a3e0fd82Sopenharmony_ci        }
218a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
219a3e0fd82Sopenharmony_ci    }
220a3e0fd82Sopenharmony_ci}
221a3e0fd82Sopenharmony_ci
222a3e0fd82Sopenharmony_civoid FlexLayout::GetCrossAxisPosY(int16_t& posY, uint16_t& count, uint16_t* rowsMaxHeight, UIView* child)
223a3e0fd82Sopenharmony_ci{
224a3e0fd82Sopenharmony_ci    if ((rowsMaxHeight == nullptr) || (child == nullptr)) {
225a3e0fd82Sopenharmony_ci        return;
226a3e0fd82Sopenharmony_ci    }
227a3e0fd82Sopenharmony_ci
228a3e0fd82Sopenharmony_ci    uint16_t i = 0;
229a3e0fd82Sopenharmony_ci    uint16_t offset = 0;
230a3e0fd82Sopenharmony_ci    int16_t top = child->GetStyle(STYLE_MARGIN_TOP);
231a3e0fd82Sopenharmony_ci    int16_t bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
232a3e0fd82Sopenharmony_ci
233a3e0fd82Sopenharmony_ci    if (secondaryAlign_ == ALIGN_START) {
234a3e0fd82Sopenharmony_ci        for (i = 0; i < count; i++) {
235a3e0fd82Sopenharmony_ci            offset += rowsMaxHeight[i];
236a3e0fd82Sopenharmony_ci        }
237a3e0fd82Sopenharmony_ci        posY = top + offset;
238a3e0fd82Sopenharmony_ci    } else if (secondaryAlign_ == ALIGN_END) {
239a3e0fd82Sopenharmony_ci        for (i = rowCount_ - 1; i > count; i--) {
240a3e0fd82Sopenharmony_ci            offset += rowsMaxHeight[i];
241a3e0fd82Sopenharmony_ci        }
242a3e0fd82Sopenharmony_ci        posY = GetHeight() - child->GetRelativeRect().GetHeight() - bottom - offset;
243a3e0fd82Sopenharmony_ci    } else {
244a3e0fd82Sopenharmony_ci        for (i = 0; i < rowCount_; i++) {
245a3e0fd82Sopenharmony_ci            offset += rowsMaxHeight[i];
246a3e0fd82Sopenharmony_ci        }
247a3e0fd82Sopenharmony_ci        offset = (rowsMaxHeight[0] - offset) / 2; // 2: half
248a3e0fd82Sopenharmony_ci        for (i = 1; i <= count; i++) {
249a3e0fd82Sopenharmony_ci            offset += (rowsMaxHeight[i - 1] + rowsMaxHeight[i]) / 2; // 2: half
250a3e0fd82Sopenharmony_ci        }
251a3e0fd82Sopenharmony_ci        posY = (GetHeight() - child->GetRelativeRect().GetHeight() - top - bottom) / 2 + top + offset; // 2: half
252a3e0fd82Sopenharmony_ci    }
253a3e0fd82Sopenharmony_ci}
254a3e0fd82Sopenharmony_ci
255a3e0fd82Sopenharmony_civoid FlexLayout::LayoutHorizontal()
256a3e0fd82Sopenharmony_ci{
257a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
258a3e0fd82Sopenharmony_ci    int16_t interval = 0;
259a3e0fd82Sopenharmony_ci    int16_t posX = 0;
260a3e0fd82Sopenharmony_ci    int16_t posY = 0;
261a3e0fd82Sopenharmony_ci    uint16_t count = 0;
262a3e0fd82Sopenharmony_ci    uint16_t widthsBuf[MAX_COUNT_DEFAULT] = {0};
263a3e0fd82Sopenharmony_ci    uint16_t maxHeightsBuf[MAX_COUNT_DEFAULT] = {0};
264a3e0fd82Sopenharmony_ci    uint16_t childsNumBuf[MAX_COUNT_DEFAULT] = {0};
265a3e0fd82Sopenharmony_ci    uint16_t* rowsWidth = widthsBuf;
266a3e0fd82Sopenharmony_ci    uint16_t* rowsMaxHeight = maxHeightsBuf;
267a3e0fd82Sopenharmony_ci    uint16_t* rowsChildNum = childsNumBuf;
268a3e0fd82Sopenharmony_ci    bool allocFlag = false;
269a3e0fd82Sopenharmony_ci
270a3e0fd82Sopenharmony_ci    if (wrap_ == WRAP) {
271a3e0fd82Sopenharmony_ci        CalRowCount();
272a3e0fd82Sopenharmony_ci        if (rowCount_ > MAX_COUNT_DEFAULT) {
273a3e0fd82Sopenharmony_ci            rowsWidth = new uint16_t[rowCount_]();
274a3e0fd82Sopenharmony_ci            rowsMaxHeight = new uint16_t[rowCount_]();
275a3e0fd82Sopenharmony_ci            rowsChildNum = new uint16_t[rowCount_]();
276a3e0fd82Sopenharmony_ci            allocFlag = true;
277a3e0fd82Sopenharmony_ci        }
278a3e0fd82Sopenharmony_ci        GetRowMaxHeight(rowCount_, rowsMaxHeight);
279a3e0fd82Sopenharmony_ci        GetRowsWidth(rowCount_, rowsWidth, rowsChildNum);
280a3e0fd82Sopenharmony_ci        GetRowStartPos(posX, interval, count, rowsWidth, rowsChildNum);
281a3e0fd82Sopenharmony_ci    } else {
282a3e0fd82Sopenharmony_ci        GetNoWrapStartPos(GetWidth(), posX, interval);
283a3e0fd82Sopenharmony_ci    }
284a3e0fd82Sopenharmony_ci
285a3e0fd82Sopenharmony_ci    while (child != nullptr) {
286a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
287a3e0fd82Sopenharmony_ci            int16_t left = child->GetStyle(STYLE_MARGIN_LEFT);
288a3e0fd82Sopenharmony_ci            int16_t right = child->GetStyle(STYLE_MARGIN_RIGHT);
289a3e0fd82Sopenharmony_ci            posX += left;
290a3e0fd82Sopenharmony_ci            if (((posX + child->GetRelativeRect().GetWidth() + right) > GetWidth()) && (wrap_ == WRAP)) {
291a3e0fd82Sopenharmony_ci                GetRowStartPos(posX, interval, ++count, rowsWidth, rowsChildNum);
292a3e0fd82Sopenharmony_ci                posX += left;
293a3e0fd82Sopenharmony_ci            }
294a3e0fd82Sopenharmony_ci
295a3e0fd82Sopenharmony_ci            GetCrossAxisPosY(posY, count, rowsMaxHeight, child);
296a3e0fd82Sopenharmony_ci            if (direction_ == LAYOUT_HOR_R) {
297a3e0fd82Sopenharmony_ci                child->SetPosition(GetWidth() - posX - child->GetRelativeRect().GetWidth() - right,
298a3e0fd82Sopenharmony_ci                                   posY - child->GetStyle(STYLE_MARGIN_TOP));
299a3e0fd82Sopenharmony_ci            } else {
300a3e0fd82Sopenharmony_ci                child->SetPosition(posX - left, posY - child->GetStyle(STYLE_MARGIN_TOP));
301a3e0fd82Sopenharmony_ci            }
302a3e0fd82Sopenharmony_ci            posX += child->GetRelativeRect().GetWidth() + right + interval;
303a3e0fd82Sopenharmony_ci            child->LayoutChildren();
304a3e0fd82Sopenharmony_ci        }
305a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
306a3e0fd82Sopenharmony_ci    }
307a3e0fd82Sopenharmony_ci
308a3e0fd82Sopenharmony_ci    if (allocFlag) {
309a3e0fd82Sopenharmony_ci        delete[] rowsWidth;
310a3e0fd82Sopenharmony_ci        delete[] rowsMaxHeight;
311a3e0fd82Sopenharmony_ci        delete[] rowsChildNum;
312a3e0fd82Sopenharmony_ci    }
313a3e0fd82Sopenharmony_ci}
314a3e0fd82Sopenharmony_ci
315a3e0fd82Sopenharmony_civoid FlexLayout::CalColumnCount()
316a3e0fd82Sopenharmony_ci{
317a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
318a3e0fd82Sopenharmony_ci    int16_t pos = 0;
319a3e0fd82Sopenharmony_ci    int16_t top;
320a3e0fd82Sopenharmony_ci    int16_t bottom;
321a3e0fd82Sopenharmony_ci
322a3e0fd82Sopenharmony_ci    columnCount_ = 1;
323a3e0fd82Sopenharmony_ci    while (child != nullptr) {
324a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
325a3e0fd82Sopenharmony_ci            child->ReMeasure();
326a3e0fd82Sopenharmony_ci            top = child->GetStyle(STYLE_MARGIN_TOP);
327a3e0fd82Sopenharmony_ci            bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
328a3e0fd82Sopenharmony_ci            pos += top;
329a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetHeight() + bottom) > GetHeight()) {
330a3e0fd82Sopenharmony_ci                pos = top;
331a3e0fd82Sopenharmony_ci                columnCount_++;
332a3e0fd82Sopenharmony_ci            }
333a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetHeight() + bottom;
334a3e0fd82Sopenharmony_ci        }
335a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
336a3e0fd82Sopenharmony_ci    }
337a3e0fd82Sopenharmony_ci}
338a3e0fd82Sopenharmony_ci
339a3e0fd82Sopenharmony_civoid FlexLayout::GetColumnMaxWidth(uint16_t size, uint16_t* maxColumnsWidth)
340a3e0fd82Sopenharmony_ci{
341a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
342a3e0fd82Sopenharmony_ci    int16_t pos = 0;
343a3e0fd82Sopenharmony_ci    int16_t left;
344a3e0fd82Sopenharmony_ci    int16_t right;
345a3e0fd82Sopenharmony_ci    int16_t bottom;
346a3e0fd82Sopenharmony_ci    uint16_t i = 0;
347a3e0fd82Sopenharmony_ci    uint16_t width = 0;
348a3e0fd82Sopenharmony_ci
349a3e0fd82Sopenharmony_ci    if ((maxColumnsWidth == nullptr) || (size > columnCount_)) {
350a3e0fd82Sopenharmony_ci        return;
351a3e0fd82Sopenharmony_ci    }
352a3e0fd82Sopenharmony_ci
353a3e0fd82Sopenharmony_ci    while (child != nullptr) {
354a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
355a3e0fd82Sopenharmony_ci            left = child->GetStyle(STYLE_MARGIN_LEFT);
356a3e0fd82Sopenharmony_ci            right = child->GetStyle(STYLE_MARGIN_RIGHT);
357a3e0fd82Sopenharmony_ci            bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
358a3e0fd82Sopenharmony_ci            pos += left;
359a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetHeight() + bottom) > GetHeight()) {
360a3e0fd82Sopenharmony_ci                pos = left;
361a3e0fd82Sopenharmony_ci                maxColumnsWidth[i] = width;
362a3e0fd82Sopenharmony_ci                width = 0;
363a3e0fd82Sopenharmony_ci                i++;
364a3e0fd82Sopenharmony_ci            }
365a3e0fd82Sopenharmony_ci            width = MATH_MAX(width, child->GetRelativeRect().GetWidth() + left + right);
366a3e0fd82Sopenharmony_ci            maxColumnsWidth[i] = width;
367a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetHeight() + bottom;
368a3e0fd82Sopenharmony_ci        }
369a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
370a3e0fd82Sopenharmony_ci    }
371a3e0fd82Sopenharmony_ci}
372a3e0fd82Sopenharmony_ci
373a3e0fd82Sopenharmony_civoid FlexLayout::GetColumnsHeight(uint16_t columnNum, uint16_t* columnsHeight, uint16_t* columnsChildNum)
374a3e0fd82Sopenharmony_ci{
375a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
376a3e0fd82Sopenharmony_ci    int16_t pos = 0;
377a3e0fd82Sopenharmony_ci    int16_t top;
378a3e0fd82Sopenharmony_ci    int16_t bottom;
379a3e0fd82Sopenharmony_ci    uint16_t columnChildNum = 0;
380a3e0fd82Sopenharmony_ci    uint16_t columnCount = 0;
381a3e0fd82Sopenharmony_ci    uint16_t height = 0;
382a3e0fd82Sopenharmony_ci
383a3e0fd82Sopenharmony_ci    if ((columnsHeight == nullptr) || (columnsChildNum == nullptr) || (columnNum > columnCount_)) {
384a3e0fd82Sopenharmony_ci        return;
385a3e0fd82Sopenharmony_ci    }
386a3e0fd82Sopenharmony_ci
387a3e0fd82Sopenharmony_ci    while (child != nullptr) {
388a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
389a3e0fd82Sopenharmony_ci            top = child->GetStyle(STYLE_MARGIN_TOP);
390a3e0fd82Sopenharmony_ci            bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
391a3e0fd82Sopenharmony_ci            pos += top;
392a3e0fd82Sopenharmony_ci            if ((pos + child->GetRelativeRect().GetHeight() + bottom) > GetHeight()) {
393a3e0fd82Sopenharmony_ci                pos = top;
394a3e0fd82Sopenharmony_ci                columnsHeight[columnCount] = height;
395a3e0fd82Sopenharmony_ci                height = 0;
396a3e0fd82Sopenharmony_ci                columnsChildNum[columnCount] = columnChildNum;
397a3e0fd82Sopenharmony_ci                columnChildNum = 0;
398a3e0fd82Sopenharmony_ci                columnCount++;
399a3e0fd82Sopenharmony_ci            }
400a3e0fd82Sopenharmony_ci            height += child->GetRelativeRect().GetHeight() + top + bottom;
401a3e0fd82Sopenharmony_ci            columnsHeight[columnCount] = height;
402a3e0fd82Sopenharmony_ci            columnChildNum++;
403a3e0fd82Sopenharmony_ci            columnsChildNum[columnCount] = columnChildNum;
404a3e0fd82Sopenharmony_ci            pos += child->GetRelativeRect().GetHeight() + bottom;
405a3e0fd82Sopenharmony_ci        }
406a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
407a3e0fd82Sopenharmony_ci    }
408a3e0fd82Sopenharmony_ci}
409a3e0fd82Sopenharmony_ci
410a3e0fd82Sopenharmony_civoid FlexLayout::GetCrossAxisPosX(int16_t& posX, uint16_t& count, uint16_t* columnsMaxWidth, UIView* child)
411a3e0fd82Sopenharmony_ci{
412a3e0fd82Sopenharmony_ci    if ((columnsMaxWidth == nullptr) || (child == nullptr)) {
413a3e0fd82Sopenharmony_ci        return;
414a3e0fd82Sopenharmony_ci    }
415a3e0fd82Sopenharmony_ci
416a3e0fd82Sopenharmony_ci    uint16_t i = 0;
417a3e0fd82Sopenharmony_ci    uint16_t offset = 0;
418a3e0fd82Sopenharmony_ci    int16_t left = child->GetStyle(STYLE_MARGIN_LEFT);
419a3e0fd82Sopenharmony_ci    int16_t right = child->GetStyle(STYLE_MARGIN_RIGHT);
420a3e0fd82Sopenharmony_ci
421a3e0fd82Sopenharmony_ci    if (secondaryAlign_ == ALIGN_START) {
422a3e0fd82Sopenharmony_ci        for (i = 0; i < count; i++) {
423a3e0fd82Sopenharmony_ci            offset += columnsMaxWidth[i];
424a3e0fd82Sopenharmony_ci        }
425a3e0fd82Sopenharmony_ci        posX = left + offset;
426a3e0fd82Sopenharmony_ci    } else if (secondaryAlign_ == ALIGN_END) {
427a3e0fd82Sopenharmony_ci        for (i = columnCount_ - 1; i > count; i--) {
428a3e0fd82Sopenharmony_ci            offset += columnsMaxWidth[i];
429a3e0fd82Sopenharmony_ci        }
430a3e0fd82Sopenharmony_ci        posX = GetWidth() - child->GetRelativeRect().GetWidth() - right - offset;
431a3e0fd82Sopenharmony_ci    } else {
432a3e0fd82Sopenharmony_ci        for (i = 0; i < columnCount_; i++) {
433a3e0fd82Sopenharmony_ci            offset += columnsMaxWidth[i];
434a3e0fd82Sopenharmony_ci        }
435a3e0fd82Sopenharmony_ci        offset = (columnsMaxWidth[0] - offset) / 2; // 2: half
436a3e0fd82Sopenharmony_ci        for (i = 1; i <= count; i++) {
437a3e0fd82Sopenharmony_ci            offset += (columnsMaxWidth[i - 1] + columnsMaxWidth[i]) / 2; // 2: half
438a3e0fd82Sopenharmony_ci        }
439a3e0fd82Sopenharmony_ci        posX = (GetWidth() - child->GetRelativeRect().GetWidth() - left - right) / 2 + left + offset; // 2: half
440a3e0fd82Sopenharmony_ci    }
441a3e0fd82Sopenharmony_ci}
442a3e0fd82Sopenharmony_ci
443a3e0fd82Sopenharmony_civoid FlexLayout::LayoutVertical()
444a3e0fd82Sopenharmony_ci{
445a3e0fd82Sopenharmony_ci    UIView* child = childrenHead_;
446a3e0fd82Sopenharmony_ci    int16_t interval = 0;
447a3e0fd82Sopenharmony_ci    int16_t posX = 0;
448a3e0fd82Sopenharmony_ci    int16_t posY = 0;
449a3e0fd82Sopenharmony_ci    uint16_t count = 0;
450a3e0fd82Sopenharmony_ci    uint16_t heightsBuf[MAX_COUNT_DEFAULT] = {0};
451a3e0fd82Sopenharmony_ci    uint16_t maxWidthsBuf[MAX_COUNT_DEFAULT] = {0};
452a3e0fd82Sopenharmony_ci    uint16_t childsNumBuf[MAX_COUNT_DEFAULT] = {0};
453a3e0fd82Sopenharmony_ci    uint16_t* columnsHeight = heightsBuf;
454a3e0fd82Sopenharmony_ci    uint16_t* columnsMaxWidth = maxWidthsBuf;
455a3e0fd82Sopenharmony_ci    uint16_t* columnsChildNum = childsNumBuf;
456a3e0fd82Sopenharmony_ci    bool allocFlag = false;
457a3e0fd82Sopenharmony_ci
458a3e0fd82Sopenharmony_ci    if (wrap_ == WRAP) {
459a3e0fd82Sopenharmony_ci        CalColumnCount();
460a3e0fd82Sopenharmony_ci        if (columnCount_ > MAX_COUNT_DEFAULT) {
461a3e0fd82Sopenharmony_ci            columnsHeight = new uint16_t[columnCount_]();
462a3e0fd82Sopenharmony_ci            columnsMaxWidth = new uint16_t[columnCount_]();
463a3e0fd82Sopenharmony_ci            columnsChildNum = new uint16_t[columnCount_]();
464a3e0fd82Sopenharmony_ci            allocFlag = true;
465a3e0fd82Sopenharmony_ci        }
466a3e0fd82Sopenharmony_ci        GetColumnMaxWidth(columnCount_, columnsMaxWidth);
467a3e0fd82Sopenharmony_ci        GetColumnsHeight(columnCount_, columnsHeight, columnsChildNum);
468a3e0fd82Sopenharmony_ci        GetColumnStartPos(posY, interval, count, columnsHeight, columnsChildNum);
469a3e0fd82Sopenharmony_ci    } else {
470a3e0fd82Sopenharmony_ci        GetNoWrapStartPos(GetHeight(), posY, interval);
471a3e0fd82Sopenharmony_ci    }
472a3e0fd82Sopenharmony_ci
473a3e0fd82Sopenharmony_ci    while (child != nullptr) {
474a3e0fd82Sopenharmony_ci        if (child->IsVisible()) {
475a3e0fd82Sopenharmony_ci            int16_t top = child->GetStyle(STYLE_MARGIN_TOP);
476a3e0fd82Sopenharmony_ci            int16_t bottom = child->GetStyle(STYLE_MARGIN_BOTTOM);
477a3e0fd82Sopenharmony_ci            posY += top;
478a3e0fd82Sopenharmony_ci            if (((posY + child->GetRelativeRect().GetHeight() + bottom) > GetHeight()) && (wrap_ == WRAP)) {
479a3e0fd82Sopenharmony_ci                GetColumnStartPos(posY, interval, ++count, columnsHeight, columnsChildNum);
480a3e0fd82Sopenharmony_ci                posY += top;
481a3e0fd82Sopenharmony_ci            }
482a3e0fd82Sopenharmony_ci
483a3e0fd82Sopenharmony_ci            GetCrossAxisPosX(posX, count, columnsMaxWidth, child);
484a3e0fd82Sopenharmony_ci            if (direction_ == LAYOUT_VER_R) {
485a3e0fd82Sopenharmony_ci                child->SetPosition(posX - child->GetStyle(STYLE_MARGIN_LEFT),
486a3e0fd82Sopenharmony_ci                                   GetHeight() - posY - child->GetRelativeRect().GetHeight() - bottom);
487a3e0fd82Sopenharmony_ci            } else {
488a3e0fd82Sopenharmony_ci                child->SetPosition(posX - child->GetStyle(STYLE_MARGIN_LEFT), posY - top);
489a3e0fd82Sopenharmony_ci            }
490a3e0fd82Sopenharmony_ci            posY += child->GetRelativeRect().GetHeight() + bottom + interval;
491a3e0fd82Sopenharmony_ci            child->LayoutChildren();
492a3e0fd82Sopenharmony_ci        }
493a3e0fd82Sopenharmony_ci        child = child->GetNextSibling();
494a3e0fd82Sopenharmony_ci    }
495a3e0fd82Sopenharmony_ci
496a3e0fd82Sopenharmony_ci    if (allocFlag) {
497a3e0fd82Sopenharmony_ci        delete[] columnsHeight;
498a3e0fd82Sopenharmony_ci        delete[] columnsMaxWidth;
499a3e0fd82Sopenharmony_ci        delete[] columnsChildNum;
500a3e0fd82Sopenharmony_ci    }
501a3e0fd82Sopenharmony_ci}
502a3e0fd82Sopenharmony_ci} // namespace OHOS
503