LMMS
Loading...
Searching...
No Matches
juce_Grid.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
32 int numImplicitLeading; // The number of implicit items before the explicit items
33};
34
39
41{
42 static float getTotalAbsoluteSize (const Array<TrackInfo>& tracks, Px gapSize) noexcept
43 {
44 float totalCellSize = 0.0f;
45
46 for (const auto& trackInfo : tracks)
47 if (! trackInfo.isFractional() || trackInfo.isAuto())
48 totalCellSize += trackInfo.getSize();
49
50 float totalGap = tracks.size() > 1 ? static_cast<float> ((tracks.size() - 1) * gapSize.pixels)
51 : 0.0f;
52
53 return totalCellSize + totalGap;
54 }
55
56 static float getRelativeUnitSize (float size, float totalAbsolute, const Array<TrackInfo>& tracks) noexcept
57 {
58 const float totalRelative = jlimit (0.0f, size, size - totalAbsolute);
59 float factorsSum = 0.0f;
60
61 for (const auto& trackInfo : tracks)
62 if (trackInfo.isFractional())
63 factorsSum += trackInfo.getSize();
64
65 jassert (factorsSum != 0.0f);
66 return totalRelative / factorsSum;
67 }
68
69 //==============================================================================
70 static float getTotalAbsoluteHeight (const Array<TrackInfo>& rowTracks, Px rowGap)
71 {
72 return getTotalAbsoluteSize (rowTracks, rowGap);
73 }
74
75 static float getTotalAbsoluteWidth (const Array<TrackInfo>& columnTracks, Px columnGap)
76 {
77 return getTotalAbsoluteSize (columnTracks, columnGap);
78 }
79
80 static float getRelativeWidthUnit (float gridWidth, Px columnGap, const Array<TrackInfo>& columnTracks)
81 {
82 return getRelativeUnitSize (gridWidth, getTotalAbsoluteWidth (columnTracks, columnGap), columnTracks);
83 }
84
85 static float getRelativeHeightUnit (float gridHeight, Px rowGap, const Array<TrackInfo>& rowTracks)
86 {
87 return getRelativeUnitSize (gridHeight, getTotalAbsoluteHeight (rowTracks, rowGap), rowTracks);
88 }
89
90 //==============================================================================
91 static bool hasAnyFractions (const Array<TrackInfo>& tracks)
92 {
93 return std::any_of (tracks.begin(),
94 tracks.end(),
95 [] (const auto& t) { return t.isFractional(); });
96 }
97
98 void computeSizes (float gridWidth, float gridHeight,
99 Px columnGapToUse, Px rowGapToUse,
100 const Tracks& tracks)
101 {
102 if (hasAnyFractions (tracks.columns.items))
103 relativeWidthUnit = getRelativeWidthUnit (gridWidth, columnGapToUse, tracks.columns.items);
104 else
105 remainingWidth = gridWidth - getTotalAbsoluteSize (tracks.columns.items, columnGapToUse);
106
107 if (hasAnyFractions (tracks.rows.items))
108 relativeHeightUnit = getRelativeHeightUnit (gridHeight, rowGapToUse, tracks.rows.items);
109 else
110 remainingHeight = gridHeight - getTotalAbsoluteSize (tracks.rows.items, rowGapToUse);
111 }
112
113 float relativeWidthUnit = 0.0f;
114 float relativeHeightUnit = 0.0f;
115 float remainingWidth = 0.0f;
116 float remainingHeight = 0.0f;
117};
118
119//==============================================================================
121{
122 enum { invalid = -999999 };
123 static constexpr auto emptyAreaCharacter = ".";
124
125 //==============================================================================
126 struct LineRange { int start, end; };
129
135
136 //==============================================================================
138 {
139 // fill line info array
140 Array<LineInfo> lines;
141
142 for (int i = 1; i <= tracks.size(); ++i)
143 {
144 const auto& currentTrack = tracks.getReference (i - 1);
145
146 if (i == 1) // start line
147 {
148 LineInfo li;
149 li.lineNames.add (currentTrack.getStartLineName());
150 lines.add (li);
151 }
152
153 if (i > 1 && i <= tracks.size()) // two lines in between tracks
154 {
155 const auto& prevTrack = tracks.getReference (i - 2);
156
157 LineInfo li;
158 li.lineNames.add (prevTrack.getEndLineName());
159 li.lineNames.add (currentTrack.getStartLineName());
160
161 lines.add (li);
162 }
163
164 if (i == tracks.size()) // end line
165 {
166 LineInfo li;
167 li.lineNames.add (currentTrack.getEndLineName());
168 lines.add (li);
169 }
170 }
171
172 jassert (lines.size() == tracks.size() + 1);
173
174 return lines;
175 }
176
177 //==============================================================================
179 const Array<TrackInfo>& tracks)
180 {
181 jassert (prop.hasAbsolute());
182
183 const auto lines = getArrayOfLinesFromTracks (tracks);
184 int count = 0;
185
186 for (int i = 0; i < lines.size(); i++)
187 {
188 for (const auto& name : lines.getReference (i).lineNames)
189 {
190 if (prop.getName() == name)
191 {
192 ++count;
193 break;
194 }
195 }
196
197 if (count == prop.getNumber())
198 return i + 1;
199 }
200
202 return count;
203 }
204
206 const Array<TrackInfo>& tracks)
207 {
208 jassert (prop.hasAbsolute());
209
210 if (prop.hasName())
211 return deduceAbsoluteLineNumberFromLineName (prop, tracks);
212
213 if (prop.getNumber() > 0)
214 return prop.getNumber();
215
216 if (prop.getNumber() < 0)
217 return tracks.size() + 2 + prop.getNumber();
218
219 // An integer value of 0 is invalid
221 return 1;
222 }
223
224 static int deduceAbsoluteLineNumberFromNamedSpan (int startLineNumber,
225 GridItem::Property propertyWithSpan,
226 const Array<TrackInfo>& tracks)
227 {
228 jassert (propertyWithSpan.hasSpan());
229
230 const auto lines = getArrayOfLinesFromTracks (tracks);
231 int count = 0;
232
233 for (int i = startLineNumber; i < lines.size(); i++)
234 {
235 for (const auto& name : lines.getReference (i).lineNames)
236 {
237 if (propertyWithSpan.getName() == name)
238 {
239 ++count;
240 break;
241 }
242 }
243
244 if (count == propertyWithSpan.getNumber())
245 return i + 1;
246 }
247
249 return count;
250 }
251
252 static int deduceAbsoluteLineNumberBasedOnSpan (int startLineNumber,
253 GridItem::Property propertyWithSpan,
254 const Array<TrackInfo>& tracks)
255 {
256 jassert (propertyWithSpan.hasSpan());
257
258 if (propertyWithSpan.hasName())
259 return deduceAbsoluteLineNumberFromNamedSpan (startLineNumber, propertyWithSpan, tracks);
260
261 return startLineNumber + propertyWithSpan.getNumber();
262 }
263
264 //==============================================================================
266 {
267 jassert (! (prop.start.hasAuto() && prop.end.hasAuto()));
268
269 if (prop.start.hasAbsolute() && prop.end.hasAuto())
270 {
271 prop.end = GridItem::Span (1);
272 }
273 else if (prop.start.hasAuto() && prop.end.hasAbsolute())
274 {
275 prop.start = GridItem::Span (1);
276 }
277
278 auto s = [&]() -> LineRange
279 {
280 if (prop.start.hasAbsolute() && prop.end.hasAbsolute())
281 {
282 return { deduceAbsoluteLineNumber (prop.start, tracks),
283 deduceAbsoluteLineNumber (prop.end, tracks) };
284 }
285
286 if (prop.start.hasAbsolute() && prop.end.hasSpan())
287 {
288 const auto start = deduceAbsoluteLineNumber (prop.start, tracks);
289 return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.end, tracks) };
290 }
291
292 if (prop.start.hasSpan() && prop.end.hasAbsolute())
293 {
294 const auto start = deduceAbsoluteLineNumber (prop.end, tracks);
295 return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.start, tracks) };
296 }
297
298 // Can't have an item with spans on both start and end.
300 return {};
301 }();
302
303 // swap if start overtakes end
304 if (s.start > s.end)
305 std::swap (s.start, s.end);
306 else if (s.start == s.end)
307 s.end = s.start + 1;
308
309 return s;
310 }
311
312 static LineArea deduceLineArea (const GridItem& item,
313 const Grid& grid,
314 const std::map<String, LineArea>& namedAreas)
315 {
316 if (item.area.isNotEmpty() && ! grid.templateAreas.isEmpty())
317 {
318 // Must be a named area!
319 jassert (namedAreas.count (item.area) != 0);
320
321 return namedAreas.at (item.area);
322 }
323
324 return { deduceLineRange (item.column, grid.templateColumns),
325 deduceLineRange (item.row, grid.templateRows) };
326 }
327
328 //==============================================================================
330 {
331 Array<StringArray> strings;
332
333 for (const auto& areaString : areasStrings)
334 strings.add (StringArray::fromTokens (areaString, false));
335
336 if (strings.size() > 0)
337 {
338 for (auto s : strings)
339 {
340 jassert (s.size() == strings[0].size()); // all rows must have the same number of columns
341 }
342 }
343
344 return strings;
345 }
346
347 static NamedArea findArea (Array<StringArray>& stringsArrays)
348 {
349 NamedArea area;
350
351 for (auto& stringArray : stringsArrays)
352 {
353 for (auto& string : stringArray)
354 {
355 // find anchor
356 if (area.name.isEmpty())
357 {
358 if (string != emptyAreaCharacter)
359 {
360 area.name = string;
361 area.lines.row.start = stringsArrays.indexOf (stringArray) + 1; // non-zero indexed;
362 area.lines.column.start = stringArray.indexOf (string) + 1; // non-zero indexed;
363
364 area.lines.row.end = stringsArrays.indexOf (stringArray) + 2;
365 area.lines.column.end = stringArray.indexOf (string) + 2;
366
367 // mark as visited
368 string = emptyAreaCharacter;
369 }
370 }
371 else
372 {
373 if (string == area.name)
374 {
375 area.lines.row.end = stringsArrays.indexOf (stringArray) + 2;
376 area.lines.column.end = stringArray.indexOf (string) + 2;
377
378 // mark as visited
379 string = emptyAreaCharacter;
380 }
381 }
382 }
383 }
384
385 return area;
386 }
387
388 //==============================================================================
389 static std::map<String, LineArea> deduceNamedAreas (const StringArray& areasStrings)
390 {
391 auto stringsArrays = parseAreasProperty (areasStrings);
392
393 std::map<String, LineArea> areas;
394
395 for (auto area = findArea (stringsArrays); area.name.isNotEmpty(); area = findArea (stringsArrays))
396 {
397 if (areas.count (area.name) == 0)
398 areas[area.name] = area.lines;
399 else
400 // Make sure your template-areas property only has one area with the same name and is well-formed
402 }
403
404 return areas;
405 }
406
407 //==============================================================================
408 static float getCoord (int trackNumber, float relativeUnit, Px gap, const Array<TrackInfo>& tracks)
409 {
410 float c = 0;
411
412 for (const auto* it = tracks.begin(); it != tracks.begin() + trackNumber; ++it)
413 c += it->getAbsoluteSize (relativeUnit) + static_cast<float> (gap.pixels);
414
415 return c;
416 }
417
418 static Rectangle<float> getCellBounds (int columnNumber, int rowNumber,
419 const Tracks& tracks,
420 SizeCalculation calculation,
422 {
423 const auto correctedColumn = columnNumber - 1 + tracks.columns.numImplicitLeading;
424 const auto correctedRow = rowNumber - 1 + tracks.rows .numImplicitLeading;
425
426 jassert (isPositiveAndBelow (correctedColumn, tracks.columns.items.size()));
427 jassert (isPositiveAndBelow (correctedRow, tracks.rows .items.size()));
428
429 return { getCoord (correctedColumn, calculation.relativeWidthUnit, columnGap, tracks.columns.items),
430 getCoord (correctedRow, calculation.relativeHeightUnit, rowGap, tracks.rows .items),
431 tracks.columns.items.getReference (correctedColumn).getAbsoluteSize (calculation.relativeWidthUnit),
432 tracks.rows .items.getReference (correctedRow) .getAbsoluteSize (calculation.relativeHeightUnit) };
433 }
434
436 int columnNumber, int rowNumber,
437 int numberOfColumns, int numberOfRows,
438 SizeCalculation calculation,
441 {
443 area.setY (area.getY() + calculation.remainingHeight);
444
446 area.setX (area.getX() + calculation.remainingWidth);
447
449 area.setY (area.getY() + calculation.remainingHeight / 2);
450
452 area.setX (area.getX() + calculation.remainingWidth / 2);
453
455 {
456 const auto shift = ((float) (rowNumber - 1) * (calculation.remainingHeight / float(numberOfRows - 1)));
457 area.setY (area.getY() + shift);
458 }
459
461 {
462 const auto shift = ((float) (columnNumber - 1) * (calculation.remainingWidth / float(numberOfColumns - 1)));
463 area.setX (area.getX() + shift);
464 }
465
467 {
468 const auto shift = ((float) rowNumber * (calculation.remainingHeight / float(numberOfRows + 1)));
469 area.setY (area.getY() + shift);
470 }
471
473 {
474 const auto shift = ((float) columnNumber * (calculation.remainingWidth / float(numberOfColumns + 1)));
475 area.setX (area.getX() + shift);
476 }
477
479 {
480 const auto inbetweenShift = calculation.remainingHeight / float(numberOfRows);
481 const auto sidesShift = inbetweenShift / 2;
482 auto shift = (float) (rowNumber - 1) * inbetweenShift + sidesShift;
483
484 area.setY (area.getY() + shift);
485 }
486
488 {
489 const auto inbetweenShift = calculation.remainingWidth / float(numberOfColumns);
490 const auto sidesShift = inbetweenShift / 2;
491 auto shift = (float) (columnNumber - 1) * inbetweenShift + sidesShift;
492
493 area.setX (area.getX() + shift);
494 }
495
496 return area;
497 }
498
501 const Tracks& tracks,
502 SizeCalculation calculation,
506 {
507 const auto findAlignedCell = [&] (int column, int row)
508 {
509 const auto cell = getCellBounds (column, row, tracks, calculation, columnGap, rowGap);
510 return alignCell (cell,
511 column,
512 row,
513 tracks.columns.items.size(),
514 tracks.rows.items.size(),
515 calculation,
518 };
519
520 const auto startCell = findAlignedCell (columnRange.start, rowRange.start);
521 const auto endCell = findAlignedCell (columnRange.end - 1, rowRange.end - 1);
522
523 const auto horizontalRange = startCell.getHorizontalRange().getUnionWith (endCell.getHorizontalRange());
524 const auto verticalRange = startCell.getVerticalRange() .getUnionWith (endCell.getVerticalRange());
525 return { horizontalRange.getStart(), verticalRange.getStart(),
526 horizontalRange.getLength(), verticalRange.getLength() };
527 }
528};
529
530template <typename Item>
531static Array<Item> operator+ (const Array<Item>& a, const Array<Item>& b)
532{
533 auto copy = a;
534 copy.addArray (b);
535 return copy;
536}
537
538//==============================================================================
540{
542
543 //==============================================================================
545 {
546 struct Cell { int column, row; };
547
548 OccupancyPlane (int highestColumnToUse, int highestRowToUse, bool isColumnFirst)
549 : highestCrossDimension (isColumnFirst ? highestRowToUse : highestColumnToUse),
550 columnFirst (isColumnFirst)
551 {}
552
553 PlacementHelpers::LineArea setCell (Cell cell, int columnSpan, int rowSpan)
554 {
555 for (int i = 0; i < columnSpan; i++)
556 for (int j = 0; j < rowSpan; j++)
557 setCell (cell.column + i, cell.row + j);
558
559 return { { cell.column, cell.column + columnSpan }, { cell.row, cell.row + rowSpan } };
560 }
561
563 {
564 return setCell (start, std::abs (end.column - start.column),
565 std::abs (end.row - start.row));
566 }
567
568 Cell nextAvailable (Cell referenceCell, int columnSpan, int rowSpan)
569 {
570 while (isOccupied (referenceCell, columnSpan, rowSpan) || isOutOfBounds (referenceCell, columnSpan, rowSpan))
571 referenceCell = advance (referenceCell);
572
573 return referenceCell;
574 }
575
576 Cell nextAvailableOnRow (Cell referenceCell, int columnSpan, int rowSpan, int rowNumber)
577 {
578 if (columnFirst && (rowNumber + rowSpan) > highestCrossDimension)
579 highestCrossDimension = rowNumber + rowSpan;
580
581 while (isOccupied (referenceCell, columnSpan, rowSpan)
582 || (referenceCell.row != rowNumber))
583 referenceCell = advance (referenceCell);
584
585 return referenceCell;
586 }
587
588 Cell nextAvailableOnColumn (Cell referenceCell, int columnSpan, int rowSpan, int columnNumber)
589 {
590 if (! columnFirst && (columnNumber + columnSpan) > highestCrossDimension)
591 highestCrossDimension = columnNumber + columnSpan;
592
593 while (isOccupied (referenceCell, columnSpan, rowSpan)
594 || (referenceCell.column != columnNumber))
595 referenceCell = advance (referenceCell);
596
597 return referenceCell;
598 }
599
600 void updateMaxCrossDimensionFromAutoPlacementItem (int columnSpan, int rowSpan)
601 {
602 highestCrossDimension = jmax (highestCrossDimension, 1 + getCrossDimension ({ columnSpan, rowSpan }));
603 }
604
605 private:
607 {
610
611 bool operator< (const SortableCell& other) const
612 {
613 if (columnFirst)
614 {
615 if (row == other.row)
616 return column < other.column;
617
618 return row < other.row;
619 }
620
621 if (row == other.row)
622 return column < other.column;
623
624 return row < other.row;
625 }
626 };
627
628 void setCell (int column, int row)
629 {
630 occupiedCells.insert ({ column, row, columnFirst });
631 }
632
633 bool isOccupied (Cell cell) const
634 {
635 return occupiedCells.count ({ cell.column, cell.row, columnFirst }) > 0;
636 }
637
638 bool isOccupied (Cell cell, int columnSpan, int rowSpan) const
639 {
640 for (int i = 0; i < columnSpan; i++)
641 for (int j = 0; j < rowSpan; j++)
642 if (isOccupied ({ cell.column + i, cell.row + j }))
643 return true;
644
645 return false;
646 }
647
648 bool isOutOfBounds (Cell cell, int columnSpan, int rowSpan) const
649 {
650 const auto highestIndexOfCell = getCrossDimension (cell) + getCrossDimension ({ columnSpan, rowSpan });
651 const auto highestIndexOfGrid = getHighestCrossDimension();
652
653 return highestIndexOfGrid < highestIndexOfCell;
654 }
655
657 {
658 Cell cell { 1, 1 };
659
660 if (occupiedCells.size() > 0)
661 cell = { occupiedCells.crbegin()->column, occupiedCells.crbegin()->row };
662
663 return std::max (getCrossDimension (cell), highestCrossDimension);
664 }
665
667 {
669 return fromDimensions (getMainDimension (cell) + 1, 1);
670
672 }
673
674 int getMainDimension (Cell cell) const { return columnFirst ? cell.column : cell.row; }
675 int getCrossDimension (Cell cell) const { return columnFirst ? cell.row : cell.column; }
676
677 Cell fromDimensions (int mainDimension, int crossDimension) const
678 {
679 if (columnFirst)
680 return { mainDimension, crossDimension };
681
682 return { crossDimension, mainDimension };
683 }
684
687 std::set<SortableCell> occupiedCells;
688 };
689
690 //==============================================================================
692 {
693 return prop.start.hasName() || prop.start.hasAbsolute() || prop.end.hasName() || prop.end.hasAbsolute();
694 }
695
696 static bool hasFullyFixedPlacement (const GridItem& item)
697 {
698 if (item.area.isNotEmpty())
699 return true;
700
701 if (isFixed (item.column) && isFixed (item.row))
702 return true;
703
704 return false;
705 }
706
707 static bool hasPartialFixedPlacement (const GridItem& item)
708 {
709 if (item.area.isNotEmpty())
710 return false;
711
712 if (isFixed (item.column) ^ isFixed (item.row))
713 return true;
714
715 return false;
716 }
717
718 static bool hasAutoPlacement (const GridItem& item)
719 {
720 return ! hasFullyFixedPlacement (item) && ! hasPartialFixedPlacement (item);
721 }
722
723 //==============================================================================
729
735
736 //==============================================================================
738 {
739 if (prop.end.hasSpan())
740 return prop.end.getNumber();
741
742 if (prop.start.hasSpan())
743 return prop.start.getNumber();
744
745 return 1;
746 }
747
748 //==============================================================================
750 {
751 const auto namedAreas = PlacementHelpers::deduceNamedAreas (grid.templateAreas);
752
753 OccupancyPlane plane (jmax (grid.templateColumns.size() + 1, 2),
754 jmax (grid.templateRows.size() + 1, 2),
756
757 ItemPlacementArray itemPlacementArray;
758 Array<GridItem*> sortedItems;
759
760 for (auto& item : grid.items)
761 sortedItems.add (&item);
762
763 std::stable_sort (sortedItems.begin(), sortedItems.end(),
764 [] (const GridItem* i1, const GridItem* i2) { return i1->order < i2->order; });
765
766 // place fixed items first
767 for (auto* item : sortedItems)
768 {
769 if (hasFullyFixedPlacement (*item))
770 {
771 const auto a = PlacementHelpers::deduceLineArea (*item, grid, namedAreas);
772 plane.setCell ({ a.column.start, a.row.start }, { a.column.end, a.row.end });
773 itemPlacementArray.add ({ item, a });
774 }
775 }
776
777 OccupancyPlane::Cell lastInsertionCell = { 1, 1 };
778
779 for (auto* item : sortedItems)
780 {
781 if (hasPartialFixedPlacement (*item))
782 {
783 if (isFixed (item->column))
784 {
785 const auto p = PlacementHelpers::deduceLineRange (item->column, grid.templateColumns);
786 const auto columnSpan = std::abs (p.start - p.end);
787 const auto rowSpan = getSpanFromAuto (item->row);
788
789 const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { p.start, 1 }
790 : lastInsertionCell;
791 const auto nextAvailableCell = plane.nextAvailableOnColumn (insertionCell, columnSpan, rowSpan, p.start);
792 const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan);
793 lastInsertionCell = nextAvailableCell;
794
795 itemPlacementArray.add ({ item, lineArea });
796 }
797 else if (isFixed (item->row))
798 {
799 const auto p = PlacementHelpers::deduceLineRange (item->row, grid.templateRows);
800 const auto columnSpan = getSpanFromAuto (item->column);
801 const auto rowSpan = std::abs (p.start - p.end);
802
803 const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { 1, p.start }
804 : lastInsertionCell;
805
806 const auto nextAvailableCell = plane.nextAvailableOnRow (insertionCell, columnSpan, rowSpan, p.start);
807 const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan);
808
809 lastInsertionCell = nextAvailableCell;
810
811 itemPlacementArray.add ({ item, lineArea });
812 }
813 }
814 }
815
816 // https://www.w3.org/TR/css-grid-1/#auto-placement-algo step 3.3
817 for (auto* item : sortedItems)
818 if (hasAutoPlacement (*item))
820
821 lastInsertionCell = { 1, 1 };
822
823 for (auto* item : sortedItems)
824 {
825 if (hasAutoPlacement (*item))
826 {
827 const auto columnSpan = getSpanFromAuto (item->column);
828 const auto rowSpan = getSpanFromAuto (item->row);
829
830 const auto nextAvailableCell = plane.nextAvailable (lastInsertionCell, columnSpan, rowSpan);
831 const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan);
832
833 if (! hasDenseAutoFlow (grid.autoFlow))
834 lastInsertionCell = nextAvailableCell;
835
836 itemPlacementArray.add ({ item, lineArea });
837 }
838 }
839
840 return itemPlacementArray;
841 }
842
843 //==============================================================================
844 template <typename Accessor>
846 {
847 if (items.isEmpty())
848 return { 1, 1 };
849
850 const auto combine = [&accessor] (const auto& acc, const auto& item)
851 {
852 const auto newRange = accessor (item);
853 return PlacementHelpers::LineRange { std::min (acc.start, newRange.start),
854 std::max (acc.end, newRange.end) };
855 };
856
857 return std::accumulate (std::next (items.begin()), items.end(), accessor (*items.begin()), combine);
858 }
859
861 {
862 return { findFullLineRange (items, [] (const auto& item) { return item.second.column; }),
863 findFullLineRange (items, [] (const auto& item) { return item.second.row; }) };
864 }
865
866 template <typename Item>
867 static Array<Item> repeated (int repeats, const Item& item)
868 {
870 result.insertMultiple (-1, item, repeats);
871 return result;
872 }
873
875 {
876 const auto fullArea = findFullLineArea (items);
877
878 const auto leadingColumns = std::max (0, 1 - fullArea.column.start);
879 const auto leadingRows = std::max (0, 1 - fullArea.row.start);
880
881 const auto trailingColumns = std::max (0, fullArea.column.end - grid.templateColumns.size() - 1);
882 const auto trailingRows = std::max (0, fullArea.row .end - grid.templateRows .size() - 1);
883
884 return { { repeated (leadingColumns, grid.autoColumns) + grid.templateColumns + repeated (trailingColumns, grid.autoColumns),
885 leadingColumns },
886 { repeated (leadingRows, grid.autoRows) + grid.templateRows + repeated (trailingRows, grid.autoRows),
887 leadingRows } };
888 }
889
890 //==============================================================================
891 static void applySizeForAutoTracks (Tracks& tracks, const ItemPlacementArray& placements)
892 {
893 const auto setSizes = [&placements] (auto& tracksInDirection, const auto& getItem, const auto& getItemSize)
894 {
895 auto& array = tracksInDirection.items;
896
897 for (int index = 0; index < array.size(); ++index)
898 {
899 if (array.getReference (index).isAuto())
900 {
901 const auto combiner = [&] (const auto acc, const auto& element)
902 {
903 const auto item = getItem (element.second);
904 const auto isNotSpan = std::abs (item.end - item.start) <= 1;
905 return isNotSpan && item.start == index + 1 - tracksInDirection.numImplicitLeading
906 ? std::max (acc, getItemSize (*element.first))
907 : acc;
908 };
909
910 array.getReference (index).size = std::accumulate (placements.begin(), placements.end(), 0.0f, combiner);
911 }
912 }
913 };
914
915 setSizes (tracks.rows,
916 [] (const auto& i) { return i.row; },
917 [] (const auto& i) { return i.height + i.margin.top + i.margin.bottom; });
918
919 setSizes (tracks.columns,
920 [] (const auto& i) { return i.column; },
921 [] (const auto& i) { return i.width + i.margin.left + i.margin.right; });
922 }
923};
924
925//==============================================================================
927{
929 const Grid& grid,
930 Rectangle<float> area)
931 {
932 // if item align is auto, inherit value from grid
933 const auto alignType = item.alignSelf == GridItem::AlignSelf::autoValue
934 ? grid.alignItems
935 : static_cast<AlignItems> (item.alignSelf);
936
937 const auto justifyType = item.justifySelf == GridItem::JustifySelf::autoValue
938 ? grid.justifyItems
939 : static_cast<JustifyItems> (item.justifySelf);
940
941 // subtract margin from area
942 area = BorderSize<float> (item.margin.top, item.margin.left, item.margin.bottom, item.margin.right)
943 .subtractedFrom (area);
944
945 // align and justify
946 auto r = area;
947
948 if (item.width != (float) GridItem::notAssigned) r.setWidth (item.width);
949 if (item.height != (float) GridItem::notAssigned) r.setHeight (item.height);
950 if (item.maxWidth != (float) GridItem::notAssigned) r.setWidth (jmin (item.maxWidth, r.getWidth()));
951 if (item.minWidth > 0.0f) r.setWidth (jmax (item.minWidth, r.getWidth()));
952 if (item.maxHeight != (float) GridItem::notAssigned) r.setHeight (jmin (item.maxHeight, r.getHeight()));
953 if (item.minHeight > 0.0f) r.setHeight (jmax (item.minHeight, r.getHeight()));
954
955 if (alignType == AlignItems::start && justifyType == JustifyItems::start)
956 return r;
957
958 if (alignType == AlignItems::end) r.setY (r.getY() + (area.getHeight() - r.getHeight()));
959 if (justifyType == JustifyItems::end) r.setX (r.getX() + (area.getWidth() - r.getWidth()));
960 if (alignType == AlignItems::center) r.setCentre (r.getCentreX(), area.getCentreY());
961 if (justifyType == JustifyItems::center) r.setCentre (area.getCentreX(), r.getCentreY());
962
963 return r;
964 }
965};
966
967//==============================================================================
969
971 : size (static_cast<float> (sizeInPixels.pixels)), isFraction (false) {}
972
974 : size ((float)fractionOfFreeSpace.fraction), isFraction (true) {}
975
976Grid::TrackInfo::TrackInfo (Px sizeInPixels, const String& endLineNameToUse) noexcept
977 : TrackInfo (sizeInPixels)
978{
979 endLineName = endLineNameToUse;
980}
981
982Grid::TrackInfo::TrackInfo (Fr fractionOfFreeSpace, const String& endLineNameToUse) noexcept
983 : TrackInfo (fractionOfFreeSpace)
984{
985 endLineName = endLineNameToUse;
986}
987
988Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Px sizeInPixels) noexcept
989 : TrackInfo (sizeInPixels)
990{
991 startLineName = startLineNameToUse;
992}
993
994Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Fr fractionOfFreeSpace) noexcept
995 : TrackInfo (fractionOfFreeSpace)
996{
997 startLineName = startLineNameToUse;
998}
999
1000Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Px sizeInPixels, const String& endLineNameToUse) noexcept
1001 : TrackInfo (startLineNameToUse, sizeInPixels)
1002{
1003 endLineName = endLineNameToUse;
1004}
1005
1006Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Fr fractionOfFreeSpace, const String& endLineNameToUse) noexcept
1007 : TrackInfo (startLineNameToUse, fractionOfFreeSpace)
1008{
1009 endLineName = endLineNameToUse;
1010}
1011
1012float Grid::TrackInfo::getAbsoluteSize (float relativeFractionalUnit) const
1013{
1014 return isFractional() ? size * relativeFractionalUnit : size;
1015}
1016
1017//==============================================================================
1019{
1020 const auto itemsAndAreas = AutoPlacement().deduceAllItems (*this);
1021
1022 auto implicitTracks = AutoPlacement::createImplicitTracks (*this, itemsAndAreas);
1023
1024 AutoPlacement::applySizeForAutoTracks (implicitTracks, itemsAndAreas);
1025
1026 SizeCalculation calculation;
1027 calculation.computeSizes (targetArea.toFloat().getWidth(),
1028 targetArea.toFloat().getHeight(),
1029 columnGap,
1030 rowGap,
1031 implicitTracks);
1032
1033 for (auto& itemAndArea : itemsAndAreas)
1034 {
1035 const auto a = itemAndArea.second;
1036 const auto areaBounds = PlacementHelpers::getAreaBounds (a.column,
1037 a.row,
1038 implicitTracks,
1039 calculation,
1042 columnGap,
1043 rowGap);
1044
1045 auto* item = itemAndArea.first;
1046 item->currentBounds = BoxAlignment::alignItem (*item, *this, areaBounds)
1047 + targetArea.toFloat().getPosition();
1048
1049 if (auto* c = item->associatedComponent)
1050 c->setBounds (item->currentBounds.toNearestIntEdges());
1051 }
1052}
1053
1054//==============================================================================
1055#if JUCE_UNIT_TESTS
1056
1057struct GridTests : public UnitTest
1058{
1059 GridTests()
1060 : UnitTest ("Grid", UnitTestCategories::gui)
1061 {}
1062
1063 void runTest() override
1064 {
1065 using Fr = Grid::Fr;
1066 using Tr = Grid::TrackInfo;
1067 using Rect = Rectangle<float>;
1068
1069 beginTest ("Layout calculation of an empty grid is a no-op");
1070 {
1071 const Rectangle<int> bounds { 100, 200 };
1072 Grid grid;
1073 grid.performLayout (bounds);
1074 }
1075
1076 {
1077 Grid grid;
1078
1079 grid.templateColumns.add (Tr (1_fr));
1080 grid.templateRows.addArray ({ Tr (20_px), Tr (1_fr) });
1081
1082 grid.items.addArray ({ GridItem().withArea (1, 1),
1083 GridItem().withArea (2, 1) });
1084
1085 grid.performLayout (Rectangle<int> (200, 400));
1086
1087 beginTest ("Layout calculation test: 1 column x 2 rows: no gap");
1088 expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 200.f, 20.0f));
1089 expect (grid.items[1].currentBounds == Rect (0.0f, 20.0f, 200.f, 380.0f));
1090
1091 grid.templateColumns.add (Tr (50_px));
1092 grid.templateRows.add (Tr (2_fr));
1093
1094 grid.items.addArray ( { GridItem().withArea (1, 2),
1095 GridItem().withArea (2, 2),
1096 GridItem().withArea (3, 1),
1097 GridItem().withArea (3, 2) });
1098
1099 grid.performLayout (Rectangle<int> (150, 170));
1100
1101 beginTest ("Layout calculation test: 2 columns x 3 rows: no gap");
1102 expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 100.0f, 20.0f));
1103 expect (grid.items[1].currentBounds == Rect (0.0f, 20.0f, 100.0f, 50.0f));
1104 expect (grid.items[2].currentBounds == Rect (100.0f, 0.0f, 50.0f, 20.0f));
1105 expect (grid.items[3].currentBounds == Rect (100.0f, 20.0f, 50.0f, 50.0f));
1106 expect (grid.items[4].currentBounds == Rect (0.0f, 70.0f, 100.0f, 100.0f));
1107 expect (grid.items[5].currentBounds == Rect (100.0f, 70.0f, 50.0f, 100.0f));
1108
1109 grid.columnGap = 20_px;
1110 grid.rowGap = 10_px;
1111
1112 grid.performLayout (Rectangle<int> (200, 310));
1113
1114 beginTest ("Layout calculation test: 2 columns x 3 rows: rowGap of 10 and columnGap of 20");
1115 expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 130.0f, 20.0f));
1116 expect (grid.items[1].currentBounds == Rect (0.0f, 30.0f, 130.0f, 90.0f));
1117 expect (grid.items[2].currentBounds == Rect (150.0f, 0.0f, 50.0f, 20.0f));
1118 expect (grid.items[3].currentBounds == Rect (150.0f, 30.0f, 50.0f, 90.0f));
1119 expect (grid.items[4].currentBounds == Rect (0.0f, 130.0f, 130.0f, 180.0f));
1120 expect (grid.items[5].currentBounds == Rect (150.0f, 130.0f, 50.0f, 180.0f));
1121 }
1122
1123 {
1124 Grid grid;
1125
1126 grid.templateColumns.addArray ({ Tr ("first", 20_px, "in"), Tr ("in", 1_fr, "in"), Tr (20_px, "last") });
1127 grid.templateRows.addArray ({ Tr (1_fr),
1128 Tr (20_px)});
1129
1130 {
1131 beginTest ("Grid items placement tests: integer and custom ident, counting forward");
1132
1133 GridItem i1, i2, i3, i4, i5;
1134 i1.column = { 1, 4 };
1135 i1.row = { 1, 2 };
1136
1137 i2.column = { 1, 3 };
1138 i2.row = { 1, 3 };
1139
1140 i3.column = { "first", "in" };
1141 i3.row = { 2, 3 };
1142
1143 i4.column = { "first", { 2, "in" } };
1144 i4.row = { 1, 2 };
1145
1146 i5.column = { "first", "last" };
1147 i5.row = { 1, 2 };
1148
1149 grid.items.addArray ({ i1, i2, i3, i4, i5 });
1150
1151 grid.performLayout ({ 140, 100 });
1152
1153 expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
1154 expect (grid.items[1].currentBounds == Rect (0.0f, 0.0f, 120.0f, 100.0f));
1155 expect (grid.items[2].currentBounds == Rect (0.0f, 80.0f, 20.0f, 20.0f));
1156 expect (grid.items[3].currentBounds == Rect (0.0f, 0.0f, 120.0f, 80.0f));
1157 expect (grid.items[4].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
1158 }
1159 }
1160
1161 {
1162 Grid grid;
1163
1164 grid.templateColumns.addArray ({ Tr ("first", 20_px, "in"), Tr ("in", 1_fr, "in"), Tr (20_px, "last") });
1165 grid.templateRows.addArray ({ Tr (1_fr),
1166 Tr (20_px)});
1167
1168 beginTest ("Grid items placement tests: integer and custom ident, counting forward, reversed end and start");
1169
1170 GridItem i1, i2, i3, i4, i5;
1171 i1.column = { 4, 1 };
1172 i1.row = { 2, 1 };
1173
1174 i2.column = { 3, 1 };
1175 i2.row = { 3, 1 };
1176
1177 i3.column = { "in", "first" };
1178 i3.row = { 3, 2 };
1179
1180 i4.column = { "first", { 2, "in" } };
1181 i4.row = { 1, 2 };
1182
1183 i5.column = { "last", "first" };
1184 i5.row = { 1, 2 };
1185
1186 grid.items.addArray ({ i1, i2, i3, i4, i5 });
1187
1188 grid.performLayout ({ 140, 100 });
1189
1190 expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
1191 expect (grid.items[1].currentBounds == Rect (0.0f, 0.0f, 120.0f, 100.0f));
1192 expect (grid.items[2].currentBounds == Rect (0.0f, 80.0f, 20.0f, 20.0f));
1193 expect (grid.items[3].currentBounds == Rect (0.0f, 0.0f, 120.0f, 80.0f));
1194 expect (grid.items[4].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
1195 }
1196
1197 {
1198 Grid grid;
1199
1200 grid.templateColumns = { Tr ("first", 20_px, "in"), Tr ("in", 1_fr, "in"), Tr (20_px, "last") };
1201 grid.templateRows = { Tr (1_fr), Tr (20_px) };
1202
1203 beginTest ("Grid items placement tests: integer, counting backward");
1204
1205 grid.items = { GridItem{}.withColumn ({ -2, -1 }).withRow ({ 1, 3 }),
1206 GridItem{}.withColumn ({ -10, -1 }).withRow ({ 1, -1 }) };
1207
1208 grid.performLayout ({ 140, 100 });
1209
1210 expect (grid.items[0].currentBounds == Rect (120.0f, 0.0f, 20.0f, 100.0f));
1211 expect (grid.items[1].currentBounds == Rect (0.0f, 0.0f, 140.0f, 100.0f));
1212 }
1213
1214 {
1215 beginTest ("Grid items placement tests: areas");
1216
1217 Grid grid;
1218
1219 grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (Fr (1_fr)), Tr (50_px) };
1220 grid.templateRows = { Tr (50_px),
1221 Tr (1_fr),
1222 Tr (50_px) };
1223
1224 grid.templateAreas = { "header header header header",
1225 "main main . sidebar",
1226 "footer footer footer footer" };
1227
1228 grid.items.addArray ({ GridItem().withArea ("header"),
1229 GridItem().withArea ("main"),
1230 GridItem().withArea ("sidebar"),
1231 GridItem().withArea ("footer"),
1232 });
1233
1234 grid.performLayout ({ 300, 150 });
1235
1236 expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 300.f, 50.f));
1237 expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
1238 expect (grid.items[2].currentBounds == Rect (250.f, 50.f, 50.f, 50.f));
1239 expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 300.f, 50.f));
1240 }
1241
1242 {
1243 beginTest ("Grid implicit rows and columns: triggered by areas");
1244
1245 Grid grid;
1246
1247 grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (1_fr), Tr (50_px) };
1248 grid.templateRows = { Tr (50_px),
1249 Tr (1_fr),
1250 Tr (50_px) };
1251
1252 grid.autoRows = Tr (30_px);
1253 grid.autoColumns = Tr (30_px);
1254
1255 grid.templateAreas = { "header header header header header",
1256 "main main . sidebar sidebar",
1257 "footer footer footer footer footer",
1258 "sub sub sub sub sub"};
1259
1260 grid.items.addArray ({ GridItem().withArea ("header"),
1261 GridItem().withArea ("main"),
1262 GridItem().withArea ("sidebar"),
1263 GridItem().withArea ("footer"),
1264 GridItem().withArea ("sub"),
1265 });
1266
1267 grid.performLayout ({ 330, 180 });
1268
1269 expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 330.f, 50.f));
1270 expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
1271 expect (grid.items[2].currentBounds == Rect (250.f, 50.f, 80.f, 50.f));
1272 expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 330.f, 50.f));
1273 expect (grid.items[4].currentBounds == Rect (0.f, 150.f, 330.f, 30.f));
1274 }
1275
1276 {
1277 beginTest ("Grid implicit rows and columns: triggered by areas");
1278
1279 Grid grid;
1280
1281 grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (1_fr), Tr (50_px) };
1282 grid.templateRows = { Tr (50_px),
1283 Tr (1_fr),
1284 Tr (50_px) };
1285
1286 grid.autoRows = Tr (1_fr);
1287 grid.autoColumns = Tr (1_fr);
1288
1289 grid.templateAreas = { "header header header header",
1290 "main main . sidebar",
1291 "footer footer footer footer" };
1292
1293 grid.items.addArray ({ GridItem().withArea ("header"),
1294 GridItem().withArea ("main"),
1295 GridItem().withArea ("sidebar"),
1296 GridItem().withArea ("footer"),
1297 GridItem().withArea (4, 5, 6, 7)
1298 });
1299
1300 grid.performLayout ({ 350, 250 });
1301
1302 expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 250.f, 50.f));
1303 expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
1304 expect (grid.items[2].currentBounds == Rect (200.f, 50.f, 50.f, 50.f));
1305 expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 250.f, 50.f));
1306 expect (grid.items[4].currentBounds == Rect (250.f, 150.f, 100.f, 100.f));
1307 }
1308
1309 {
1310 beginTest ("Grid implicit rows and columns: triggered by out-of-bounds indices");
1311
1312 Grid grid;
1313
1314 grid.templateColumns = { Tr (1_fr), Tr (1_fr) };
1315 grid.templateRows = { Tr (60_px), Tr (60_px) };
1316
1317 grid.autoColumns = Tr (20_px);
1318 grid.autoRows = Tr (1_fr);
1319
1320 grid.items = { GridItem{}.withColumn ({ 5, 8 }).withRow ({ -5, -4 }),
1321 GridItem{}.withColumn ({ 4, 7 }).withRow ({ -4, -3 }),
1322 GridItem{}.withColumn ({ -2, -1 }).withRow ({ 4, 5 }) };
1323
1324 grid.performLayout ({ 500, 400 });
1325
1326 // -3 -2 -1
1327 // 1 2 3 4 5 6 7 8
1328 // -5 +---+---+---+---+---+---+---+ 0
1329 // | | | | | 0 | 0 | 0 |
1330 // -4 +---+---+---+---+---+---+---+ 70
1331 // | | | | 1 | 1 | 1 | |
1332 // -3 1 +---+---+---+---+---+---+---+ 140
1333 // | x | x | | | | | |
1334 // -2 2 +---+---+---+---+---+---+---+ 200 y positions
1335 // | x | x | | | | | |
1336 // -1 3 +---+---+---+---+---+---+---+ 260
1337 // | | | | | | | |
1338 // 4 +---+---+---+---+---+---+---+ 330
1339 // | | 2 | | | | | |
1340 // 5 +---+---+---+---+---+---+---+ 400
1341 //
1342 // 0 200 400 420 440 460 480 500
1343 // x positions
1344 //
1345 // The cells marked "x" are the explicit cells specified by the template rows
1346 // and columns.
1347 //
1348 // The cells marked 0/1/2 correspond to the GridItems at those indices in the
1349 // items array.
1350 //
1351 // Note that negative indices count back from the last explicit line
1352 // number in that direction, so "2" and "-2" both correspond to the same line.
1353
1354 expect (grid.items[0].currentBounds == Rect (440.0f, 0.0f, 60.0f, 70.0f));
1355 expect (grid.items[1].currentBounds == Rect (420.0f, 70.0f, 60.0f, 70.0f));
1356 expect (grid.items[2].currentBounds == Rect (200.0f, 330.0f, 200.0f, 70.0f));
1357 }
1358 }
1359};
1360
1361static GridTests gridUnitTests;
1362
1363#endif
1364
1365} // namespace juce
#define copy(x)
Definition ADnoteParameters.cpp:1011
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
uint8_t a
Definition Spc_Cpu.h:141
static celltype cell[MAXCELLS]
Definition adlibemu.c:89
Definition juce_Array.h:56
int size() const noexcept
Definition juce_Array.h:215
ElementType * begin() noexcept
Definition juce_Array.h:328
ElementType * end() noexcept
Definition juce_Array.h:344
int indexOf(ParameterType elementToLookFor) const
Definition juce_Array.h:382
void add(const ElementType &newElement)
Definition juce_Array.h:418
ElementType & getReference(int index) noexcept
Definition juce_Array.h:267
Definition juce_BorderSize.h:42
Rectangle< ValueType > subtractedFrom(const Rectangle< ValueType > &original) const noexcept
Definition juce_BorderSize.h:101
TrackInfo autoColumns
Definition juce_Grid.h:193
void performLayout(Rectangle< int >)
Definition juce_Grid.cpp:1018
AutoFlow autoFlow
Definition juce_Grid.h:176
JustifyItems justifyItems
Definition juce_Grid.h:164
Grid()=default
JustifyItems
Definition juce_Grid.h:105
@ end
Definition juce_Grid.h:107
@ center
Definition juce_Grid.h:108
@ start
Definition juce_Grid.h:106
TrackInfo autoRows
Definition juce_Grid.h:190
Array< TrackInfo > templateRows
Definition juce_Grid.h:184
Px columnGap
Definition juce_Grid.h:196
JustifyContent justifyContent
Definition juce_Grid.h:170
JustifyContent
Definition juce_Grid.h:123
@ end
Definition juce_Grid.h:125
@ center
Definition juce_Grid.h:126
@ spaceBetween
Definition juce_Grid.h:129
@ spaceAround
Definition juce_Grid.h:128
@ spaceEvenly
Definition juce_Grid.h:130
StringArray templateAreas
Definition juce_Grid.h:187
AlignContent
Definition juce_Grid.h:135
@ end
Definition juce_Grid.h:137
@ center
Definition juce_Grid.h:138
@ spaceBetween
Definition juce_Grid.h:141
@ spaceAround
Definition juce_Grid.h:140
@ spaceEvenly
Definition juce_Grid.h:142
Array< TrackInfo > templateColumns
Definition juce_Grid.h:181
AlignContent alignContent
Definition juce_Grid.h:173
AlignItems alignItems
Definition juce_Grid.h:167
Px rowGap
Definition juce_Grid.h:198
AlignItems
Definition juce_Grid.h:114
@ end
Definition juce_Grid.h:116
@ center
Definition juce_Grid.h:117
@ start
Definition juce_Grid.h:115
AutoFlow
Definition juce_Grid.h:147
@ column
Definition juce_Grid.h:149
@ rowDense
Definition juce_Grid.h:150
@ columnDense
Definition juce_Grid.h:151
Array< GridItem > items
Definition juce_Grid.h:205
Definition juce_GridItem.h:36
float maxHeight
Definition juce_GridItem.h:172
float width
Definition juce_GridItem.h:166
String area
Definition juce_GridItem.h:156
@ autoValue
Definition juce_GridItem.h:121
float minHeight
Definition juce_GridItem.h:171
float height
Definition juce_GridItem.h:170
StartAndEndProperty row
Definition juce_GridItem.h:153
@ notAssigned
Definition juce_GridItem.h:162
float minWidth
Definition juce_GridItem.h:167
StartAndEndProperty column
Definition juce_GridItem.h:150
float maxWidth
Definition juce_GridItem.h:168
Margin margin
Definition juce_GridItem.h:189
JustifySelf justifySelf
Definition juce_GridItem.h:142
@ autoValue
Definition juce_GridItem.h:111
AlignSelf alignSelf
Definition juce_GridItem.h:147
Definition juce_Rectangle.h:67
Rectangle< float > toFloat() const noexcept
Definition juce_Rectangle.h:873
Point< ValueType > getPosition() const noexcept
Definition juce_Rectangle.h:161
ValueType getCentreX() const noexcept
Definition juce_Rectangle.h:145
ValueType getHeight() const noexcept
Definition juce_Rectangle.h:136
ValueType getCentreY() const noexcept
Definition juce_Rectangle.h:148
ValueType getX() const noexcept
Definition juce_Rectangle.h:127
ValueType getWidth() const noexcept
Definition juce_Rectangle.h:133
void setX(ValueType newX) noexcept
Definition juce_Rectangle.h:195
void setY(ValueType newY) noexcept
Definition juce_Rectangle.h:198
ValueType getY() const noexcept
Definition juce_Rectangle.h:130
Definition juce_StringArray.h:35
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition juce_StringArray.cpp:387
void add(String stringToAdd)
Definition juce_StringArray.cpp:136
bool isEmpty() const noexcept
Definition juce_StringArray.h:139
Definition juce_String.h:53
bool isEmpty() const noexcept
Definition juce_String.h:310
bool isNotEmpty() const noexcept
Definition juce_String.h:316
Definition juce_UnitTest.h:70
struct huft * t
Definition inflate.c:943
register unsigned j
Definition inflate.c:1576
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
static const char * name
Definition pugl.h:1582
virtual ASIOError start()=0
#define jassert(expression)
#define jassertfalse
Definition juce_UnitTestCategories.h:27
Definition carla_juce.cpp:31
constexpr Type jmin(Type a, Type b)
Definition juce_MathsFunctions.h:106
constexpr Type jmax(Type a, Type b)
Definition juce_MathsFunctions.h:94
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Definition juce_RangedDirectoryIterator.h:184
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Definition juce_MathsFunctions.h:262
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Definition juce_MathsFunctions.h:279
@ column
Definition juce_AccessibilityRole.h:52
@ row
Definition juce_AccessibilityRole.h:53
#define true
Definition ordinals.h:82
GUI::ui_handle_t gui
Definition main.cpp:50
Definition juce_Grid.cpp:30
int numImplicitLeading
Definition juce_Grid.cpp:32
Array< Grid::TrackInfo > items
Definition juce_Grid.cpp:31
int row
Definition juce_Grid.cpp:546
int column
Definition juce_Grid.cpp:546
Definition juce_Grid.cpp:545
int highestCrossDimension
Definition juce_Grid.cpp:685
PlacementHelpers::LineArea setCell(Cell start, Cell end)
Definition juce_Grid.cpp:562
PlacementHelpers::LineArea setCell(Cell cell, int columnSpan, int rowSpan)
Definition juce_Grid.cpp:553
std::set< SortableCell > occupiedCells
Definition juce_Grid.cpp:687
bool isOccupied(Cell cell) const
Definition juce_Grid.cpp:633
Cell advance(Cell cell) const
Definition juce_Grid.cpp:666
void updateMaxCrossDimensionFromAutoPlacementItem(int columnSpan, int rowSpan)
Definition juce_Grid.cpp:600
Cell fromDimensions(int mainDimension, int crossDimension) const
Definition juce_Grid.cpp:677
bool columnFirst
Definition juce_Grid.cpp:686
Cell nextAvailable(Cell referenceCell, int columnSpan, int rowSpan)
Definition juce_Grid.cpp:568
int getHighestCrossDimension() const
Definition juce_Grid.cpp:656
void setCell(int column, int row)
Definition juce_Grid.cpp:628
Cell nextAvailableOnColumn(Cell referenceCell, int columnSpan, int rowSpan, int columnNumber)
Definition juce_Grid.cpp:588
bool isOutOfBounds(Cell cell, int columnSpan, int rowSpan) const
Definition juce_Grid.cpp:648
bool isOccupied(Cell cell, int columnSpan, int rowSpan) const
Definition juce_Grid.cpp:638
int getCrossDimension(Cell cell) const
Definition juce_Grid.cpp:675
int getMainDimension(Cell cell) const
Definition juce_Grid.cpp:674
Cell nextAvailableOnRow(Cell referenceCell, int columnSpan, int rowSpan, int rowNumber)
Definition juce_Grid.cpp:576
OccupancyPlane(int highestColumnToUse, int highestRowToUse, bool isColumnFirst)
Definition juce_Grid.cpp:548
Definition juce_Grid.cpp:540
ItemPlacementArray deduceAllItems(Grid &grid) const
Definition juce_Grid.cpp:749
static int getSpanFromAuto(GridItem::StartAndEndProperty prop)
Definition juce_Grid.cpp:737
static bool isColumnAutoFlow(AutoFlow autoFlow)
Definition juce_Grid.cpp:730
static bool hasFullyFixedPlacement(const GridItem &item)
Definition juce_Grid.cpp:696
static bool hasPartialFixedPlacement(const GridItem &item)
Definition juce_Grid.cpp:707
static bool hasAutoPlacement(const GridItem &item)
Definition juce_Grid.cpp:718
static Array< Item > repeated(int repeats, const Item &item)
Definition juce_Grid.cpp:867
Array< std::pair< GridItem *, PlacementHelpers::LineArea > > ItemPlacementArray
Definition juce_Grid.cpp:541
static PlacementHelpers::LineRange findFullLineRange(const ItemPlacementArray &items, Accessor &&accessor)
Definition juce_Grid.cpp:845
static void applySizeForAutoTracks(Tracks &tracks, const ItemPlacementArray &placements)
Definition juce_Grid.cpp:891
static PlacementHelpers::LineArea findFullLineArea(const ItemPlacementArray &items)
Definition juce_Grid.cpp:860
static Tracks createImplicitTracks(const Grid &grid, const ItemPlacementArray &items)
Definition juce_Grid.cpp:874
static bool hasDenseAutoFlow(AutoFlow autoFlow)
Definition juce_Grid.cpp:724
static bool isFixed(GridItem::StartAndEndProperty prop)
Definition juce_Grid.cpp:691
Definition juce_Grid.cpp:927
static Rectangle< float > alignItem(const GridItem &item, const Grid &grid, Rectangle< float > area)
Definition juce_Grid.cpp:928
Definition juce_Grid.h:56
Definition juce_Grid.cpp:127
LineRange column
Definition juce_Grid.cpp:127
LineRange row
Definition juce_Grid.cpp:127
Definition juce_Grid.cpp:128
StringArray lineNames
Definition juce_Grid.cpp:128
Definition juce_Grid.cpp:126
int end
Definition juce_Grid.cpp:126
int start
Definition juce_Grid.cpp:126
Definition juce_Grid.cpp:131
LineArea lines
Definition juce_Grid.cpp:133
String name
Definition juce_Grid.cpp:132
Definition juce_Grid.cpp:121
static int deduceAbsoluteLineNumberBasedOnSpan(int startLineNumber, GridItem::Property propertyWithSpan, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:252
static Rectangle< float > alignCell(Rectangle< float > area, int columnNumber, int rowNumber, int numberOfColumns, int numberOfRows, SizeCalculation calculation, AlignContent alignContent, JustifyContent justifyContent)
Definition juce_Grid.cpp:435
@ invalid
Definition juce_Grid.cpp:122
static Array< LineInfo > getArrayOfLinesFromTracks(const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:137
static LineArea deduceLineArea(const GridItem &item, const Grid &grid, const std::map< String, LineArea > &namedAreas)
Definition juce_Grid.cpp:312
static Array< StringArray > parseAreasProperty(const StringArray &areasStrings)
Definition juce_Grid.cpp:329
static int deduceAbsoluteLineNumberFromLineName(GridItem::Property prop, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:178
static int deduceAbsoluteLineNumber(GridItem::Property prop, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:205
static NamedArea findArea(Array< StringArray > &stringsArrays)
Definition juce_Grid.cpp:347
static LineRange deduceLineRange(GridItem::StartAndEndProperty prop, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:265
static std::map< String, LineArea > deduceNamedAreas(const StringArray &areasStrings)
Definition juce_Grid.cpp:389
static Rectangle< float > getAreaBounds(PlacementHelpers::LineRange columnRange, PlacementHelpers::LineRange rowRange, const Tracks &tracks, SizeCalculation calculation, AlignContent alignContent, JustifyContent justifyContent, Px columnGap, Px rowGap)
Definition juce_Grid.cpp:499
static Rectangle< float > getCellBounds(int columnNumber, int rowNumber, const Tracks &tracks, SizeCalculation calculation, Px columnGap, Px rowGap)
Definition juce_Grid.cpp:418
static constexpr auto emptyAreaCharacter
Definition juce_Grid.cpp:123
static float getCoord(int trackNumber, float relativeUnit, Px gap, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:408
static int deduceAbsoluteLineNumberFromNamedSpan(int startLineNumber, GridItem::Property propertyWithSpan, const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:224
Definition juce_Grid.h:45
long double pixels
Definition juce_Grid.h:51
Definition juce_Grid.cpp:41
static float getTotalAbsoluteWidth(const Array< TrackInfo > &columnTracks, Px columnGap)
Definition juce_Grid.cpp:75
static float getTotalAbsoluteSize(const Array< TrackInfo > &tracks, Px gapSize) noexcept
Definition juce_Grid.cpp:42
static float getRelativeUnitSize(float size, float totalAbsolute, const Array< TrackInfo > &tracks) noexcept
Definition juce_Grid.cpp:56
float relativeWidthUnit
Definition juce_Grid.cpp:113
float relativeHeightUnit
Definition juce_Grid.cpp:114
float remainingWidth
Definition juce_Grid.cpp:115
float remainingHeight
Definition juce_Grid.cpp:116
void computeSizes(float gridWidth, float gridHeight, Px columnGapToUse, Px rowGapToUse, const Tracks &tracks)
Definition juce_Grid.cpp:98
static bool hasAnyFractions(const Array< TrackInfo > &tracks)
Definition juce_Grid.cpp:91
static float getTotalAbsoluteHeight(const Array< TrackInfo > &rowTracks, Px rowGap)
Definition juce_Grid.cpp:70
static float getRelativeHeightUnit(float gridHeight, Px rowGap, const Array< TrackInfo > &rowTracks)
Definition juce_Grid.cpp:85
static float getRelativeWidthUnit(float gridWidth, Px columnGap, const Array< TrackInfo > &columnTracks)
Definition juce_Grid.cpp:80
bool isFraction
Definition juce_Grid.h:96
bool hasKeyword
Definition juce_Grid.h:97
String endLineName
Definition juce_Grid.h:99
float getAbsoluteSize(float relativeFractionalUnit) const
Definition juce_Grid.cpp:1012
TrackInfo() noexcept
Definition juce_Grid.cpp:968
bool isFractional() const noexcept
Definition juce_Grid.h:83
float size
Definition juce_Grid.h:95
String startLineName
Definition juce_Grid.h:99
float right
Definition juce_GridItem.h:183
float top
Definition juce_GridItem.h:184
float left
Definition juce_GridItem.h:182
float bottom
Definition juce_GridItem.h:185
Definition juce_GridItem.h:70
bool hasName() const noexcept
Definition juce_GridItem.h:88
int getNumber() const noexcept
Definition juce_GridItem.h:90
bool hasAuto() const noexcept
Definition juce_GridItem.h:87
const String & getName() const noexcept
Definition juce_GridItem.h:89
bool hasSpan() const noexcept
Definition juce_GridItem.h:85
bool hasAbsolute() const noexcept
Definition juce_GridItem.h:86
Definition juce_GridItem.h:43
Definition juce_GridItem.h:101
Property start
Definition juce_GridItem.h:101
Property end
Definition juce_GridItem.h:101
Definition juce_Grid.cpp:36
AllTracksIncludingImplicit rows
Definition juce_Grid.cpp:37
AllTracksIncludingImplicit columns
Definition juce_Grid.cpp:37
void Rectangle(HDC ctx, int l, int t, int r, int b)
Definition swell-gdi-generic.cpp:279
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
int r
Definition crypt.c:458
b
Definition crypt.c:628
ulg size
Definition extract.c:2350
int result
Definition process.c:1455
_WDL_CSTRING_PREFIX void INT_PTR count
Definition wdlcstring.h:263