Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / layout / juce_StretchableLayoutManager.cpp
blob5bb29fee51602ff8ebe021c85c27a400f0e41ec8
1 /*
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"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_StretchableLayoutManager.h"
33 //==============================================================================
34 StretchableLayoutManager::StretchableLayoutManager()
35 : totalSize (0)
39 StretchableLayoutManager::~StretchableLayoutManager()
43 //==============================================================================
44 void StretchableLayoutManager::clearAllItems()
46 items.clear();
47 totalSize = 0;
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;
62 int i;
63 for (i = 0; i < items.size(); ++i)
64 if (items.getUnchecked (i)->itemIndex > itemIndex)
65 break;
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,
77 double& minimumSize,
78 double& maximumSize,
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;
88 return true;
91 return false;
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
104 int pos = 0;
106 for (int i = 0; i < itemIndex; ++i)
108 const ItemLayoutProperties* const layout = getInfoFor (i);
110 if (layout != nullptr)
111 pos += layout->currentSize;
114 return pos;
117 int StretchableLayoutManager::getItemCurrentAbsoluteSize (const int itemIndex) const
119 const ItemLayoutProperties* const layout = getInfoFor (itemIndex);
121 if (layout != nullptr)
122 return layout->currentSize;
124 return 0;
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;
134 return 0;
137 void StretchableLayoutManager::setItemPosition (const int itemIndex,
138 int newPosition)
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();
159 break;
164 //==============================================================================
165 void StretchableLayoutManager::layOutComponents (Component** const components,
166 int numComponents,
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];
182 if (c != nullptr)
184 if (i == numComponents - 1)
186 // if it's the last item, crop it to exactly fit the available space..
187 if (resizeOtherDimension)
189 if (vertically)
190 c->setBounds (x, pos, w, jmax (layout->currentSize, h - pos));
191 else
192 c->setBounds (pos, y, jmax (layout->currentSize, w - pos), h);
194 else
196 if (vertically)
197 c->setBounds (c->getX(), pos, c->getWidth(), jmax (layout->currentSize, h - pos));
198 else
199 c->setBounds (pos, c->getY(), jmax (layout->currentSize, w - pos), c->getHeight());
202 else
204 if (resizeOtherDimension)
206 if (vertically)
207 c->setBounds (x, pos, w, layout->currentSize);
208 else
209 c->setBounds (pos, y, layout->currentSize, h);
211 else
213 if (vertically)
214 c->setBounds (c->getX(), pos, c->getWidth(), layout->currentSize);
215 else
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);
234 return nullptr;
237 int StretchableLayoutManager::fitComponentsIntoSpace (const int startIndex,
238 const int endIndex,
239 const int availableSpace,
240 int startPos)
242 // calculate the total sizes
243 int i;
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;
297 if (extraWanted > 0)
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)
314 break;
317 // ..and calculate the end position
318 for (i = startIndex; i < endIndex; ++i)
320 ItemLayoutProperties* const layout = items.getUnchecked(i);
321 startPos += layout->currentSize;
324 return startPos;
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)
362 if (size < 0)
363 size *= -totalSpace;
365 return roundToInt (size);
368 END_JUCE_NAMESPACE