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