fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
860
modules/juce_gui_basics/layout/juce_FlexBox.cpp
Normal file
860
modules/juce_gui_basics/layout/juce_FlexBox.cpp
Normal file
@ -0,0 +1,860 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
Reference in New Issue
Block a user