123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
- JUCE is an open source library subject to commercial or open-source
- licensing.
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
- ==============================================================================
- */
- namespace juce
- {
- struct FlexBoxLayoutCalculation
- {
- using Coord = double;
- FlexBoxLayoutCalculation (FlexBox& fb, Coord w, Coord h)
- : owner (fb), parentWidth (w), parentHeight (h), numItems (owner.items.size()),
- isRowDirection (fb.flexDirection == FlexBox::Direction::row
- || fb.flexDirection == FlexBox::Direction::rowReverse),
- containerLineLength (isRowDirection ? parentWidth : parentHeight)
- {
- lineItems.calloc (numItems * numItems);
- lineInfo.calloc (numItems);
- }
- struct ItemWithState
- {
- ItemWithState (FlexItem& source) noexcept : item (&source) {}
- FlexItem* item;
- Coord lockedWidth = 0, lockedHeight = 0;
- Coord lockedMarginLeft = 0, lockedMarginRight = 0, lockedMarginTop = 0, lockedMarginBottom = 0;
- Coord preferredWidth = 0, preferredHeight = 0;
- bool locked = false;
- void resetItemLockedSize() noexcept
- {
- lockedWidth = preferredWidth;
- lockedHeight = preferredHeight;
- lockedMarginLeft = getValueOrZeroIfAuto (item->margin.left);
- lockedMarginRight = getValueOrZeroIfAuto (item->margin.right);
- lockedMarginTop = getValueOrZeroIfAuto (item->margin.top);
- lockedMarginBottom = getValueOrZeroIfAuto (item->margin.bottom);
- }
- void setWidthChecked (Coord newWidth) noexcept
- {
- if (isAssigned (item->maxWidth)) newWidth = jmin (newWidth, static_cast<Coord> (item->maxWidth));
- if (isAssigned (item->minWidth)) newWidth = jmax (newWidth, static_cast<Coord> (item->minWidth));
- lockedWidth = newWidth;
- }
- void setHeightChecked (Coord newHeight) noexcept
- {
- if (isAssigned (item->maxHeight)) newHeight = jmin (newHeight, (Coord) item->maxHeight);
- if (isAssigned (item->minHeight)) newHeight = jmax (newHeight, (Coord) item->minHeight);
- lockedHeight = newHeight;
- }
- };
- struct RowInfo
- {
- int numItems;
- Coord crossSize, lineY, totalLength;
- };
- FlexBox& owner;
- const Coord parentWidth, parentHeight;
- const int numItems;
- const bool isRowDirection;
- const Coord containerLineLength;
- int numberOfRows = 1;
- Coord containerCrossLength = 0;
- HeapBlock<ItemWithState*> lineItems;
- HeapBlock<RowInfo> lineInfo;
- Array<ItemWithState> itemStates;
- ItemWithState& getItem (int x, int y) const noexcept { return *lineItems[y * numItems + x]; }
- static bool isAuto (Coord value) noexcept { return value == FlexItem::autoValue; }
- static bool isAssigned (Coord value) noexcept { return value != FlexItem::notAssigned; }
- static Coord getValueOrZeroIfAuto (Coord value) noexcept { return isAuto (value) ? Coord() : value; }
- //==============================================================================
- void createStates()
- {
- itemStates.ensureStorageAllocated (numItems);
- for (auto& item : owner.items)
- itemStates.add (item);
- std::stable_sort (itemStates.begin(), itemStates.end(),
- [] (const ItemWithState& i1, const ItemWithState& i2) { return i1.item->order < i2.item->order; });
- for (auto& item : itemStates)
- {
- item.preferredWidth = getPreferredWidth (item);
- item.preferredHeight = getPreferredHeight (item);
- }
- }
- void initialiseItems() noexcept
- {
- if (owner.flexWrap == FlexBox::Wrap::noWrap) // for single-line, all items go in line 1
- {
- lineInfo[0].numItems = numItems;
- int i = 0;
- for (auto& item : itemStates)
- {
- item.resetItemLockedSize();
- lineItems[i++] = &item;
- }
- }
- else // if multi-line, group the flexbox items into multiple lines
- {
- auto currentLength = containerLineLength;
- int column = 0, row = 0;
- bool firstRow = true;
- for (auto& item : itemStates)
- {
- item.resetItemLockedSize();
- const auto flexitemLength = getItemLength (item);
- if (flexitemLength > currentLength)
- {
- if (! firstRow)
- row++;
- if (row >= numItems)
- break;
- column = 0;
- currentLength = containerLineLength;
- numberOfRows = jmax (numberOfRows, row + 1);
- }
- currentLength -= flexitemLength;
- lineItems[row * numItems + column] = &item;
- ++column;
- lineInfo[row].numItems = jmax (lineInfo[row].numItems, column);
- firstRow = false;
- }
- }
- }
- void resolveFlexibleLengths() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- resetRowItems (row);
- for (int maxLoops = numItems; --maxLoops >= 0;)
- {
- resetUnlockedRowItems (row);
- if (layoutRowItems (row))
- break;
- }
- }
- }
- void resolveAutoMarginsOnMainAxis() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- Coord allFlexGrow = 0;
- const auto numColumns = lineInfo[row].numItems;
- const auto remainingLength = containerLineLength - lineInfo[row].totalLength;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isRowDirection)
- {
- if (isAuto (item.item->margin.left)) ++allFlexGrow;
- if (isAuto (item.item->margin.right)) ++allFlexGrow;
- }
- else
- {
- if (isAuto (item.item->margin.top)) ++allFlexGrow;
- if (isAuto (item.item->margin.bottom)) ++allFlexGrow;
- }
- }
- auto changeUnitWidth = remainingLength / allFlexGrow;
- if (changeUnitWidth > 0)
- {
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isRowDirection)
- {
- if (isAuto (item.item->margin.left)) item.lockedMarginLeft = changeUnitWidth;
- if (isAuto (item.item->margin.right)) item.lockedMarginRight = changeUnitWidth;
- }
- else
- {
- if (isAuto (item.item->margin.top)) item.lockedMarginTop = changeUnitWidth;
- if (isAuto (item.item->margin.bottom)) item.lockedMarginBottom = changeUnitWidth;
- }
- }
- }
- }
- }
- void calculateCrossSizesByLine() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- Coord maxSize = 0;
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- maxSize = jmax (maxSize, isRowDirection ? item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom
- : item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight);
- }
- lineInfo[row].crossSize = maxSize;
- }
- }
- void calculateCrossSizeOfAllItems() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isAssigned (item.item->maxHeight) && item.lockedHeight > item.item->maxHeight)
- item.lockedHeight = item.item->maxHeight;
- if (isAssigned (item.item->maxWidth) && item.lockedWidth > item.item->maxWidth)
- item.lockedWidth = item.item->maxWidth;
- }
- }
- }
- void alignLinesPerAlignContent() noexcept
- {
- containerCrossLength = isRowDirection ? parentHeight : parentWidth;
- if (owner.alignContent == FlexBox::AlignContent::flexStart)
- {
- for (int row = 0; row < numberOfRows; ++row)
- for (int row2 = row; row2 < numberOfRows; ++row2)
- lineInfo[row].lineY = row == 0 ? 0 : lineInfo[row - 1].lineY + lineInfo[row - 1].crossSize;
- }
- else if (owner.alignContent == FlexBox::AlignContent::flexEnd)
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- Coord crossHeights = 0;
- for (int row2 = row; row2 < numberOfRows; ++row2)
- crossHeights += lineInfo[row2].crossSize;
- lineInfo[row].lineY = containerCrossLength - crossHeights;
- }
- }
- else
- {
- Coord totalHeight = 0;
- for (int row = 0; row < numberOfRows; ++row)
- totalHeight += lineInfo[row].crossSize;
- if (owner.alignContent == FlexBox::AlignContent::stretch)
- {
- const auto difference = jmax (Coord(), (containerCrossLength - totalHeight) / numberOfRows);
- for (int row = 0; row < numberOfRows; ++row)
- {
- lineInfo[row].crossSize += difference;
- lineInfo[row].lineY = row == 0 ? 0 : lineInfo[row - 1].lineY + lineInfo[row - 1].crossSize;
- }
- }
- else if (owner.alignContent == FlexBox::AlignContent::center)
- {
- const auto additionalength = (containerCrossLength - totalHeight) / 2;
- for (int row = 0; row < numberOfRows; ++row)
- lineInfo[row].lineY = row == 0 ? additionalength : lineInfo[row - 1].lineY + lineInfo[row - 1].crossSize;
- }
- else if (owner.alignContent == FlexBox::AlignContent::spaceBetween)
- {
- const auto additionalength = numberOfRows <= 1 ? Coord() : jmax (Coord(), (containerCrossLength - totalHeight)
- / static_cast<Coord> (numberOfRows - 1));
- lineInfo[0].lineY = 0;
- for (int row = 1; row < numberOfRows; ++row)
- lineInfo[row].lineY += additionalength + lineInfo[row - 1].lineY + lineInfo[row - 1].crossSize;
- }
- else if (owner.alignContent == FlexBox::AlignContent::spaceAround)
- {
- const auto additionalength = numberOfRows <= 1 ? Coord() : jmax (Coord(), (containerCrossLength - totalHeight)
- / static_cast<Coord> (2 + (2 * (numberOfRows - 1))));
- lineInfo[0].lineY = additionalength;
- for (int row = 1; row < numberOfRows; ++row)
- lineInfo[row].lineY += (2 * additionalength) + lineInfo[row - 1].lineY + lineInfo[row - 1].crossSize;
- }
- }
- }
- void resolveAutoMarginsOnCrossAxis() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto numColumns = lineInfo[row].numItems;
- const auto crossSizeForLine = lineInfo[row].crossSize;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isRowDirection)
- {
- if (isAuto (item.item->margin.top) && isAuto (item.item->margin.bottom))
- item.lockedMarginTop = (crossSizeForLine - item.lockedHeight) / 2;
- else if (isAuto (item.item->margin.top))
- item.lockedMarginTop = crossSizeForLine - item.lockedHeight - item.item->margin.bottom;
- }
- else if (isAuto (item.item->margin.left) && isAuto (item.item->margin.right))
- {
- item.lockedMarginLeft = jmax (Coord(), (crossSizeForLine - item.lockedWidth) / 2);
- }
- else if (isAuto (item.item->margin.top))
- {
- item.lockedMarginLeft = jmax (Coord(), crossSizeForLine - item.lockedHeight - item.item->margin.bottom);
- }
- }
- }
- }
- void alignItemsInCrossAxisInLinesPerAlignItems() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto numColumns = lineInfo[row].numItems;
- const auto lineSize = lineInfo[row].crossSize;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (item.item->alignSelf == FlexItem::AlignSelf::autoAlign)
- {
- if (owner.alignItems == FlexBox::AlignItems::stretch)
- {
- item.lockedMarginTop = item.item->margin.top;
- if (isRowDirection)
- item.setHeightChecked (lineSize - item.item->margin.top - item.item->margin.bottom);
- else
- item.setWidthChecked (lineSize - item.item->margin.left - item.item->margin.right);
- }
- else if (owner.alignItems == FlexBox::AlignItems::flexStart)
- {
- item.lockedMarginTop = item.item->margin.top;
- }
- else if (owner.alignItems == FlexBox::AlignItems::flexEnd)
- {
- if (isRowDirection)
- item.lockedMarginTop = lineSize - item.lockedHeight - item.item->margin.bottom;
- else
- item.lockedMarginLeft = lineSize - item.lockedWidth - item.item->margin.right;
- }
- else if (owner.alignItems == FlexBox::AlignItems::center)
- {
- if (isRowDirection)
- item.lockedMarginTop = (lineSize - item.lockedHeight - item.item->margin.top - item.item->margin.bottom) / 2;
- else
- item.lockedMarginLeft = (lineSize - item.lockedWidth - item.item->margin.left - item.item->margin.right) / 2;
- }
- }
- }
- }
- }
- void alignLinesPerAlignSelf() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto numColumns = lineInfo[row].numItems;
- const auto lineSize = lineInfo[row].crossSize;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (! isAuto (item.item->margin.top))
- {
- if (item.item->alignSelf == FlexItem::AlignSelf::flexStart)
- {
- if (isRowDirection)
- item.lockedMarginTop = item.item->margin.top;
- else
- item.lockedMarginLeft = item.item->margin.left;
- }
- else if (item.item->alignSelf == FlexItem::AlignSelf::flexEnd)
- {
- if (isRowDirection)
- item.lockedMarginTop = lineSize - item.lockedHeight - item.item->margin.bottom;
- else
- item.lockedMarginLeft = lineSize - item.lockedWidth - item.item->margin.right;
- }
- else if (item.item->alignSelf == FlexItem::AlignSelf::center)
- {
- if (isRowDirection)
- item.lockedMarginTop = item.item->margin.top + (lineSize - item.lockedHeight - item.item->margin.top - item.item->margin.bottom) / 2;
- else
- item.lockedMarginLeft = item.item->margin.left + (lineSize - item.lockedWidth - item.item->margin.left - item.item->margin.right) / 2;
- }
- else if (item.item->alignSelf == FlexItem::AlignSelf::stretch)
- {
- item.lockedMarginTop = item.item->margin.top;
- item.lockedMarginLeft = item.item->margin.left;
- if (isRowDirection)
- item.setHeightChecked (isAssigned (item.item->height) ? getPreferredHeight (item)
- : lineSize - item.item->margin.top - item.item->margin.bottom);
- else
- item.setWidthChecked (isAssigned (item.item->width) ? getPreferredWidth (item)
- : lineSize - item.item->margin.left - item.item->margin.right);
- }
- }
- }
- }
- }
- void alignItemsByJustifyContent() noexcept
- {
- Coord additionalMarginRight = 0, additionalMarginLeft = 0;
- recalculateTotalItemLengthPerLineArray();
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto numColumns = lineInfo[row].numItems;
- Coord x = 0;
- if (owner.justifyContent == FlexBox::JustifyContent::flexEnd)
- {
- x = containerLineLength - lineInfo[row].totalLength;
- }
- else if (owner.justifyContent == FlexBox::JustifyContent::center)
- {
- x = (containerLineLength - lineInfo[row].totalLength) / 2;
- }
- else if (owner.justifyContent == FlexBox::JustifyContent::spaceBetween)
- {
- additionalMarginRight
- = jmax (Coord(), (containerLineLength - lineInfo[row].totalLength) / jmax (1, numColumns - 1));
- }
- else if (owner.justifyContent == FlexBox::JustifyContent::spaceAround)
- {
- additionalMarginLeft = additionalMarginRight
- = jmax (Coord(), (containerLineLength - lineInfo[row].totalLength) / jmax (1, 2 * numColumns));
- }
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isRowDirection)
- {
- item.lockedMarginLeft += additionalMarginLeft;
- item.lockedMarginRight += additionalMarginRight;
- item.item->currentBounds.setPosition ((float) (x + item.lockedMarginLeft), (float) item.lockedMarginTop);
- x += item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight;
- }
- else
- {
- item.lockedMarginTop += additionalMarginLeft;
- item.lockedMarginBottom += additionalMarginRight;
- item.item->currentBounds.setPosition ((float) item.lockedMarginLeft, (float) (x + item.lockedMarginTop));
- x += item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom;
- }
- }
- }
- }
- void layoutAllItems() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- const auto lineY = lineInfo[row].lineY;
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (isRowDirection)
- item.item->currentBounds.setY ((float) (lineY + item.lockedMarginTop));
- else
- item.item->currentBounds.setX ((float) (lineY + item.lockedMarginLeft));
- item.item->currentBounds.setSize ((float) item.lockedWidth,
- (float) item.lockedHeight);
- }
- }
- reverseLocations();
- reverseWrap();
- }
- private:
- void resetRowItems (const int row) noexcept
- {
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- resetItem (getItem (column, row));
- }
- void resetUnlockedRowItems (const int row) noexcept
- {
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (! item.locked)
- resetItem (item);
- }
- }
- void resetItem (ItemWithState& item) noexcept
- {
- item.locked = false;
- item.lockedWidth = getPreferredWidth (item);
- item.lockedHeight = getPreferredHeight (item);
- }
- bool layoutRowItems (const int row) noexcept
- {
- const auto numColumns = lineInfo[row].numItems;
- auto flexContainerLength = containerLineLength;
- Coord totalItemsLength = 0, totalFlexGrow = 0, totalFlexShrink = 0;
- for (int column = 0; column < numColumns; ++column)
- {
- const auto& item = getItem (column, row);
- if (item.locked)
- {
- flexContainerLength -= getItemLength (item);
- }
- else
- {
- totalItemsLength += getItemLength (item);
- totalFlexGrow += item.item->flexGrow;
- totalFlexShrink += item.item->flexShrink;
- }
- }
- Coord changeUnit = 0;
- const auto difference = flexContainerLength - totalItemsLength;
- const bool positiveFlexibility = difference > 0;
- if (positiveFlexibility)
- {
- if (totalFlexGrow != 0.0)
- changeUnit = difference / totalFlexGrow;
- }
- else
- {
- if (totalFlexShrink != 0.0)
- changeUnit = difference / totalFlexShrink;
- }
- bool ok = true;
- for (int column = 0; column < numColumns; ++column)
- {
- auto& item = getItem (column, row);
- if (! item.locked)
- if (! addToItemLength (item, (positiveFlexibility ? item.item->flexGrow
- : item.item->flexShrink) * changeUnit, row))
- ok = false;
- }
- return ok;
- }
- void recalculateTotalItemLengthPerLineArray() noexcept
- {
- for (int row = 0; row < numberOfRows; ++row)
- {
- lineInfo[row].totalLength = 0;
- const auto numColumns = lineInfo[row].numItems;
- for (int column = 0; column < numColumns; ++column)
- {
- const auto& item = getItem (column, row);
- lineInfo[row].totalLength += isRowDirection ? item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight
- : item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom;
- }
- }
- }
- void reverseLocations() noexcept
- {
- if (owner.flexDirection == FlexBox::Direction::rowReverse)
- {
- for (auto& item : owner.items)
- item.currentBounds.setX ((float) (containerLineLength - item.currentBounds.getRight()));
- }
- else if (owner.flexDirection == FlexBox::Direction::columnReverse)
- {
- for (auto& item : owner.items)
- item.currentBounds.setY ((float) (containerLineLength - item.currentBounds.getBottom()));
- }
- }
- void reverseWrap() noexcept
- {
- if (owner.flexWrap == FlexBox::Wrap::wrapReverse)
- {
- if (isRowDirection)
- {
- for (auto& item : owner.items)
- item.currentBounds.setY ((float) (containerCrossLength - item.currentBounds.getBottom()));
- }
- else
- {
- for (auto& item : owner.items)
- item.currentBounds.setX ((float) (containerCrossLength - item.currentBounds.getRight()));
- }
- }
- }
- Coord getItemLength (const ItemWithState& item) const noexcept
- {
- return isRowDirection ? item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight
- : item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom;
- }
- Coord getItemCrossSize (const ItemWithState& item) const noexcept
- {
- return isRowDirection ? item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom
- : item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight;
- }
- bool addToItemLength (ItemWithState& item, const Coord length, int row) const noexcept
- {
- bool ok = false;
- if (isRowDirection)
- {
- const auto prefWidth = getPreferredWidth (item);
- if (isAssigned (item.item->maxWidth) && item.item->maxWidth < prefWidth + length)
- {
- item.lockedWidth = item.item->maxWidth;
- item.locked = true;
- }
- else if (isAssigned (prefWidth) && item.item->minWidth > prefWidth + length)
- {
- item.lockedWidth = item.item->minWidth;
- item.locked = true;
- }
- else
- {
- ok = true;
- item.lockedWidth = prefWidth + length;
- }
- lineInfo[row].totalLength += item.lockedWidth + item.lockedMarginLeft + item.lockedMarginRight;
- }
- else
- {
- const auto prefHeight = getPreferredHeight (item);
- if (isAssigned (item.item->maxHeight) && item.item->maxHeight < prefHeight + length)
- {
- item.lockedHeight = item.item->maxHeight;
- item.locked = true;
- }
- else if (isAssigned (prefHeight) && item.item->minHeight > prefHeight + length)
- {
- item.lockedHeight = item.item->minHeight;
- item.locked = true;
- }
- else
- {
- ok = true;
- item.lockedHeight = prefHeight + length;
- }
- lineInfo[row].totalLength += item.lockedHeight + item.lockedMarginTop + item.lockedMarginBottom;
- }
- return ok;
- }
- Coord getPreferredWidth (const ItemWithState& itemWithState) const noexcept
- {
- const auto& item = *itemWithState.item;
- auto preferredWidth = (item.flexBasis > 0 && isRowDirection)
- ? item.flexBasis
- : (isAssigned (item.width) ? item.width : item.minWidth);
- if (isAssigned (item.minWidth) && preferredWidth < item.minWidth) return item.minWidth;
- if (isAssigned (item.maxWidth) && preferredWidth > item.maxWidth) return item.maxWidth;
- return preferredWidth;
- }
- Coord getPreferredHeight (const ItemWithState& itemWithState) const noexcept
- {
- const auto& item = *itemWithState.item;
- auto preferredHeight = (item.flexBasis > 0 && ! isRowDirection)
- ? item.flexBasis
- : (isAssigned (item.height) ? item.height : item.minHeight);
- if (isAssigned (item.minHeight) && preferredHeight < item.minHeight) return item.minHeight;
- if (isAssigned (item.maxHeight) && preferredHeight > item.maxHeight) return item.maxHeight;
- return preferredHeight;
- }
- };
- //==============================================================================
- FlexBox::FlexBox() noexcept {}
- FlexBox::~FlexBox() noexcept {}
- FlexBox::FlexBox (JustifyContent jc) noexcept : justifyContent (jc) {}
- FlexBox::FlexBox (Direction d, Wrap w, AlignContent ac, AlignItems ai, JustifyContent jc) noexcept
- : flexDirection (d), flexWrap (w), alignContent (ac), alignItems (ai), justifyContent (jc)
- {
- }
- void FlexBox::performLayout (Rectangle<float> targetArea)
- {
- if (! items.isEmpty())
- {
- FlexBoxLayoutCalculation layout (*this, targetArea.getWidth(), targetArea.getHeight());
- layout.createStates();
- layout.initialiseItems();
- layout.resolveFlexibleLengths();
- layout.resolveAutoMarginsOnMainAxis();
- layout.calculateCrossSizesByLine();
- layout.calculateCrossSizeOfAllItems();
- layout.alignLinesPerAlignContent();
- layout.resolveAutoMarginsOnCrossAxis();
- layout.alignItemsInCrossAxisInLinesPerAlignItems();
- layout.alignLinesPerAlignSelf();
- layout.alignItemsByJustifyContent();
- layout.layoutAllItems();
- for (auto& item : items)
- {
- item.currentBounds += targetArea.getPosition();
- if (auto* comp = item.associatedComponent)
- comp->setBounds (Rectangle<int>::leftTopRightBottom ((int) item.currentBounds.getX(),
- (int) item.currentBounds.getY(),
- (int) item.currentBounds.getRight(),
- (int) item.currentBounds.getBottom()));
- if (auto* box = item.associatedFlexBox)
- box->performLayout (item.currentBounds);
- }
- }
- }
- void FlexBox::performLayout (Rectangle<int> targetArea)
- {
- performLayout (targetArea.toFloat());
- }
- //==============================================================================
- FlexItem::FlexItem() noexcept {}
- FlexItem::FlexItem (float w, float h) noexcept : currentBounds (w, h), minWidth (w), minHeight (h) {}
- FlexItem::FlexItem (float w, float h, Component& c) noexcept : FlexItem (w, h) { associatedComponent = &c; }
- FlexItem::FlexItem (float w, float h, FlexBox& fb) noexcept : FlexItem (w, h) { associatedFlexBox = &fb; }
- FlexItem::FlexItem (Component& c) noexcept : associatedComponent (&c) {}
- FlexItem::FlexItem (FlexBox& fb) noexcept : associatedFlexBox (&fb) {}
- FlexItem::Margin::Margin() noexcept : left(), right(), top(), bottom() {}
- FlexItem::Margin::Margin (float v) noexcept : left (v), right (v), top (v), bottom (v) {}
- FlexItem::Margin::Margin (float t, float r, float b, float l) noexcept : left (l), right (r), top (t), bottom (b) {}
- //==============================================================================
- FlexItem FlexItem::withFlex (float newFlexGrow) const noexcept
- {
- auto fi = *this;
- fi.flexGrow = newFlexGrow;
- return fi;
- }
- FlexItem FlexItem::withFlex (float newFlexGrow, float newFlexShrink) const noexcept
- {
- auto fi = withFlex (newFlexGrow);
- fi.flexShrink = newFlexShrink;
- return fi;
- }
- FlexItem FlexItem::withFlex (float newFlexGrow, float newFlexShrink, float newFlexBasis) const noexcept
- {
- auto fi = withFlex (newFlexGrow, newFlexShrink);
- fi.flexBasis = newFlexBasis;
- return fi;
- }
- FlexItem FlexItem::withWidth (float newWidth) const noexcept { auto fi = *this; fi.width = newWidth; return fi; }
- FlexItem FlexItem::withMinWidth (float newMinWidth) const noexcept { auto fi = *this; fi.minWidth = newMinWidth; return fi; }
- FlexItem FlexItem::withMaxWidth (float newMaxWidth) const noexcept { auto fi = *this; fi.maxWidth = newMaxWidth; return fi; }
- FlexItem FlexItem::withMinHeight (float newMinHeight) const noexcept { auto fi = *this; fi.minHeight = newMinHeight; return fi; }
- FlexItem FlexItem::withMaxHeight (float newMaxHeight) const noexcept { auto fi = *this; fi.maxHeight = newMaxHeight; return fi; }
- FlexItem FlexItem::withHeight (float newHeight) const noexcept { auto fi = *this; fi.height = newHeight; return fi; }
- FlexItem FlexItem::withMargin (Margin m) const noexcept { auto fi = *this; fi.margin = m; return fi; }
- FlexItem FlexItem::withOrder (int newOrder) const noexcept { auto fi = *this; fi.order = newOrder; return fi; }
- FlexItem FlexItem::withAlignSelf (AlignSelf a) const noexcept { auto fi = *this; fi.alignSelf = a; return fi; }
- } // namespace juce
|