1 // Basic class for canvas layouts
3 // Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Library General Public License for more details.
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <simgear/debug/logstream.hxx>
27 //----------------------------------------------------------------------------
28 void Layout::removeItem(const LayoutItemRef& item)
31 while( LayoutItemRef child = itemAt(i) )
34 return (void)takeAt(i);
40 //----------------------------------------------------------------------------
47 //----------------------------------------------------------------------------
48 SGRecti Layout::alignmentRect(const SGRecti& geom) const
50 return alignment() == AlignFill
51 // Without explicit alignment (default == AlignFill) use the whole
52 // available space and let the layout and its items distribute the
56 // Otherwise align according to flags.
57 : LayoutItem::alignmentRect(geom);
60 //----------------------------------------------------------------------------
61 void Layout::ItemData::reset()
77 //----------------------------------------------------------------------------
78 int Layout::ItemData::hfw(int w) const
81 return layout_item->heightForWidth(w);
83 return layout_item->sizeHint().y();
86 //----------------------------------------------------------------------------
87 int Layout::ItemData::mhfw(int w) const
90 return layout_item->minimumHeightForWidth(w);
92 return layout_item->minimumSize().y();
95 //----------------------------------------------------------------------------
105 //----------------------------------------------------------------------------
106 void Layout::contentsRectChanged(const SGRecti& rect)
110 _flags &= ~LAYOUT_DIRTY;
113 //----------------------------------------------------------------------------
114 void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
116 const int num_children = static_cast<int>(items.size());
121 "Layout::distribute(" << space.size << "px for "
122 << num_children << " items, s.t."
123 << " min=" << space.min_size
124 << ", hint=" << space.size_hint
125 << ", max=" << space.max_size << ")" );
127 if( space.size < space.min_size )
130 SG_LOG( SG_GUI, SG_WARN, "Layout: not enough size (not implemented)");
132 else if( space.size < space.max_size )
137 bool less_then_hint = space.size < space.size_hint;
139 // Give min_size/size_hint to all items
140 _space_left = space.size
141 - (less_then_hint ? space.min_size : space.size_hint);
142 for(int i = 0; i < num_children; ++i)
144 ItemData& d = items[i];
148 d.size = less_then_hint ? d.min_size : d.size_hint;
149 d.padding = d.padding_orig;
150 d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
155 i << ") initial=" << d.size
156 << ", min=" << d.min_size
157 << ", hint=" << d.size_hint
158 << ", max=" << d.max_size
167 _sum_stretch += d.stretch;
168 _space_stretch += d.size;
172 // Distribute remaining space to increase the size of each item up to its
173 // size_hint/max_size
174 while( _space_left > 0 )
176 if( _num_not_done <= 0 )
178 SG_LOG(SG_GUI, SG_WARN, "space left, but no more items?");
182 int space_per_element = std::max(1, _space_left / _num_not_done);
184 SG_LOG(SG_GUI, SG_DEBUG, "space/element=" << space_per_element);
186 for(int i = 0; i < num_children; ++i)
188 ItemData& d = items[i];
195 i << ") left=" << _space_left
196 << ", not_done=" << _num_not_done
197 << ", sum=" << _sum_stretch
198 << ", stretch=" << _space_stretch
199 << ", stretch/unit=" << _space_stretch / std::max(1, _sum_stretch)
205 if( _sum_stretch > 0 && d.stretch <= 0 )
210 int max_size = less_then_hint ? d.size_hint : d.max_size;
212 if( _sum_stretch > 0 )
214 target_size = (d.stretch * (_space_left + _space_stretch))
217 // Item would be smaller than minimum size or larger than maximum
218 // size, so just keep bounded size and ignore stretch factor
219 if( target_size <= d.size || target_size >= max_size )
222 _sum_stretch -= d.stretch;
223 _space_stretch -= d.size;
225 if( target_size >= max_size )
226 target_size = max_size;
228 target_size = d.size;
231 _space_stretch += target_size - d.size;
235 // Give space evenly to all remaining elements in this round
236 target_size = d.size + std::min(_space_left, space_per_element);
238 if( target_size >= max_size )
241 target_size = max_size;
245 int old_size = d.size;
246 d.size = target_size;
247 _space_left -= d.size - old_size;
254 if( _sum_stretch <= 0 && d.stretch > 0 )
255 // Distribute remaining space evenly to all non-stretchable items
264 _space_left = space.size - space.max_size;
266 for(int i = 0; i < num_children; ++i)
268 if( !items[i].visible )
273 if( items[i].has_align )
280 "Distributing excess space:"
281 " not_done=" << _num_not_done
282 << ", num_align=" << num_align
283 << ", space_left=" << _space_left
286 for(int i = 0; i < num_children; ++i)
288 ItemData& d = items[i];
292 d.padding = d.padding_orig;
299 // Equally distribute superfluous space and let each child items
300 // alignment handle the exact usage.
301 space_add = _space_left / num_align;
306 else if( num_align <= 0 )
308 // Add superfluous space as padding
309 space_add = _space_left
310 // Padding after last child...
311 / (_num_not_done + 1);
314 d.padding += space_add;
317 _space_left -= space_add;
321 SG_LOG(SG_GUI, SG_DEBUG, "distribute:");
322 for(int i = 0; i < num_children; ++i)
324 ItemData const& d = items[i];
326 SG_LOG(SG_GUI, SG_DEBUG, i << ") pad=" << d.padding
327 << ", size= " << d.size);
329 SG_LOG(SG_GUI, SG_DEBUG, i << ") [hidden]");
333 } // namespace canvas
334 } // namespace simgear