2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
30 #include "juce_StretchableLayoutManager.h"
33 //==============================================================================
34 StretchableLayoutManager::StretchableLayoutManager()
39 StretchableLayoutManager::~StretchableLayoutManager()
43 //==============================================================================
44 void StretchableLayoutManager::clearAllItems()
50 void StretchableLayoutManager::setItemLayout (const int itemIndex
,
51 const double minimumSize
,
52 const double maximumSize
,
53 const double preferredSize
)
55 ItemLayoutProperties
* layout
= getInfoFor (itemIndex
);
57 if (layout
== nullptr)
59 layout
= new ItemLayoutProperties();
60 layout
->itemIndex
= itemIndex
;
63 for (i
= 0; i
< items
.size(); ++i
)
64 if (items
.getUnchecked (i
)->itemIndex
> itemIndex
)
67 items
.insert (i
, layout
);
70 layout
->minSize
= minimumSize
;
71 layout
->maxSize
= maximumSize
;
72 layout
->preferredSize
= preferredSize
;
73 layout
->currentSize
= 0;
76 bool StretchableLayoutManager::getItemLayout (const int itemIndex
,
79 double& preferredSize
) const
81 const ItemLayoutProperties
* const layout
= getInfoFor (itemIndex
);
83 if (layout
!= nullptr)
85 minimumSize
= layout
->minSize
;
86 maximumSize
= layout
->maxSize
;
87 preferredSize
= layout
->preferredSize
;
94 //==============================================================================
95 void StretchableLayoutManager::setTotalSize (const int newTotalSize
)
97 totalSize
= newTotalSize
;
99 fitComponentsIntoSpace (0, items
.size(), totalSize
, 0);
102 int StretchableLayoutManager::getItemCurrentPosition (const int itemIndex
) const
106 for (int i
= 0; i
< itemIndex
; ++i
)
108 const ItemLayoutProperties
* const layout
= getInfoFor (i
);
110 if (layout
!= nullptr)
111 pos
+= layout
->currentSize
;
117 int StretchableLayoutManager::getItemCurrentAbsoluteSize (const int itemIndex
) const
119 const ItemLayoutProperties
* const layout
= getInfoFor (itemIndex
);
121 if (layout
!= nullptr)
122 return layout
->currentSize
;
127 double StretchableLayoutManager::getItemCurrentRelativeSize (const int itemIndex
) const
129 const ItemLayoutProperties
* const layout
= getInfoFor (itemIndex
);
131 if (layout
!= nullptr)
132 return -layout
->currentSize
/ (double) totalSize
;
137 void StretchableLayoutManager::setItemPosition (const int itemIndex
,
140 for (int i
= items
.size(); --i
>= 0;)
142 const ItemLayoutProperties
* const layout
= items
.getUnchecked(i
);
144 if (layout
->itemIndex
== itemIndex
)
146 int realTotalSize
= jmax (totalSize
, getMinimumSizeOfItems (0, items
.size()));
147 const int minSizeAfterThisComp
= getMinimumSizeOfItems (i
, items
.size());
148 const int maxSizeAfterThisComp
= getMaximumSizeOfItems (i
+ 1, items
.size());
150 newPosition
= jmax (newPosition
, totalSize
- maxSizeAfterThisComp
- layout
->currentSize
);
151 newPosition
= jmin (newPosition
, realTotalSize
- minSizeAfterThisComp
);
153 int endPos
= fitComponentsIntoSpace (0, i
, newPosition
, 0);
155 endPos
+= layout
->currentSize
;
157 fitComponentsIntoSpace (i
+ 1, items
.size(), totalSize
- endPos
, endPos
);
158 updatePrefSizesToMatchCurrentPositions();
164 //==============================================================================
165 void StretchableLayoutManager::layOutComponents (Component
** const components
,
167 int x
, int y
, int w
, int h
,
168 const bool vertically
,
169 const bool resizeOtherDimension
)
171 setTotalSize (vertically
? h
: w
);
172 int pos
= vertically
? y
: x
;
174 for (int i
= 0; i
< numComponents
; ++i
)
176 const ItemLayoutProperties
* const layout
= getInfoFor (i
);
178 if (layout
!= nullptr)
180 Component
* const c
= components
[i
];
184 if (i
== numComponents
- 1)
186 // if it's the last item, crop it to exactly fit the available space..
187 if (resizeOtherDimension
)
190 c
->setBounds (x
, pos
, w
, jmax (layout
->currentSize
, h
- pos
));
192 c
->setBounds (pos
, y
, jmax (layout
->currentSize
, w
- pos
), h
);
197 c
->setBounds (c
->getX(), pos
, c
->getWidth(), jmax (layout
->currentSize
, h
- pos
));
199 c
->setBounds (pos
, c
->getY(), jmax (layout
->currentSize
, w
- pos
), c
->getHeight());
204 if (resizeOtherDimension
)
207 c
->setBounds (x
, pos
, w
, layout
->currentSize
);
209 c
->setBounds (pos
, y
, layout
->currentSize
, h
);
214 c
->setBounds (c
->getX(), pos
, c
->getWidth(), layout
->currentSize
);
216 c
->setBounds (pos
, c
->getY(), layout
->currentSize
, c
->getHeight());
221 pos
+= layout
->currentSize
;
227 //==============================================================================
228 StretchableLayoutManager::ItemLayoutProperties
* StretchableLayoutManager::getInfoFor (const int itemIndex
) const
230 for (int i
= items
.size(); --i
>= 0;)
231 if (items
.getUnchecked(i
)->itemIndex
== itemIndex
)
232 return items
.getUnchecked(i
);
237 int StretchableLayoutManager::fitComponentsIntoSpace (const int startIndex
,
239 const int availableSpace
,
242 // calculate the total sizes
244 double totalIdealSize
= 0.0;
245 int totalMinimums
= 0;
247 for (i
= startIndex
; i
< endIndex
; ++i
)
249 ItemLayoutProperties
* const layout
= items
.getUnchecked (i
);
251 layout
->currentSize
= sizeToRealSize (layout
->minSize
, totalSize
);
253 totalMinimums
+= layout
->currentSize
;
254 totalIdealSize
+= sizeToRealSize (layout
->preferredSize
, totalSize
);
257 if (totalIdealSize
<= 0)
258 totalIdealSize
= 1.0;
260 // now calc the best sizes..
261 int extraSpace
= availableSpace
- totalMinimums
;
263 while (extraSpace
> 0)
265 int numWantingMoreSpace
= 0;
266 int numHavingTakenExtraSpace
= 0;
268 // first figure out how many comps want a slice of the extra space..
269 for (i
= startIndex
; i
< endIndex
; ++i
)
271 ItemLayoutProperties
* const layout
= items
.getUnchecked (i
);
273 double sizeWanted
= sizeToRealSize (layout
->preferredSize
, totalSize
);
275 const int bestSize
= jlimit (layout
->currentSize
,
276 jmax (layout
->currentSize
,
277 sizeToRealSize (layout
->maxSize
, totalSize
)),
278 roundToInt (sizeWanted
* availableSpace
/ totalIdealSize
));
280 if (bestSize
> layout
->currentSize
)
281 ++numWantingMoreSpace
;
284 // ..share out the extra space..
285 for (i
= startIndex
; i
< endIndex
; ++i
)
287 ItemLayoutProperties
* const layout
= items
.getUnchecked (i
);
289 double sizeWanted
= sizeToRealSize (layout
->preferredSize
, totalSize
);
291 int bestSize
= jlimit (layout
->currentSize
,
292 jmax (layout
->currentSize
, sizeToRealSize (layout
->maxSize
, totalSize
)),
293 roundToInt (sizeWanted
* availableSpace
/ totalIdealSize
));
295 const int extraWanted
= bestSize
- layout
->currentSize
;
299 const int extraAllowed
= jmin (extraWanted
,
300 extraSpace
/ jmax (1, numWantingMoreSpace
));
302 if (extraAllowed
> 0)
304 ++numHavingTakenExtraSpace
;
305 --numWantingMoreSpace
;
307 layout
->currentSize
+= extraAllowed
;
308 extraSpace
-= extraAllowed
;
313 if (numHavingTakenExtraSpace
<= 0)
317 // ..and calculate the end position
318 for (i
= startIndex
; i
< endIndex
; ++i
)
320 ItemLayoutProperties
* const layout
= items
.getUnchecked(i
);
321 startPos
+= layout
->currentSize
;
327 int StretchableLayoutManager::getMinimumSizeOfItems (const int startIndex
,
328 const int endIndex
) const
330 int totalMinimums
= 0;
332 for (int i
= startIndex
; i
< endIndex
; ++i
)
333 totalMinimums
+= sizeToRealSize (items
.getUnchecked (i
)->minSize
, totalSize
);
335 return totalMinimums
;
338 int StretchableLayoutManager::getMaximumSizeOfItems (const int startIndex
, const int endIndex
) const
340 int totalMaximums
= 0;
342 for (int i
= startIndex
; i
< endIndex
; ++i
)
343 totalMaximums
+= sizeToRealSize (items
.getUnchecked (i
)->maxSize
, totalSize
);
345 return totalMaximums
;
348 void StretchableLayoutManager::updatePrefSizesToMatchCurrentPositions()
350 for (int i
= 0; i
< items
.size(); ++i
)
352 ItemLayoutProperties
* const layout
= items
.getUnchecked (i
);
354 layout
->preferredSize
355 = (layout
->preferredSize
< 0) ? getItemCurrentRelativeSize (i
)
356 : getItemCurrentAbsoluteSize (i
);
360 int StretchableLayoutManager::sizeToRealSize (double size
, int totalSpace
)
365 return roundToInt (size
);