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 //----------------------------------------------------------------------------
30 if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
35 _flags &= ~LAYOUT_DIRTY;
38 //----------------------------------------------------------------------------
39 void Layout::invalidate()
41 LayoutItem::invalidate();
42 _flags |= LAYOUT_DIRTY;
45 //----------------------------------------------------------------------------
46 void Layout::setGeometry(const SGRecti& geom)
48 if( geom == _geometry )
52 _flags |= LAYOUT_DIRTY;
57 //----------------------------------------------------------------------------
58 void Layout::removeItem(const LayoutItemRef& item)
61 while( LayoutItemRef child = itemAt(i) )
64 return (void)takeAt(i);
70 //----------------------------------------------------------------------------
77 //----------------------------------------------------------------------------
78 void Layout::ItemData::reset()
92 //----------------------------------------------------------------------------
93 int Layout::ItemData::hfw(int w) const
96 return layout_item->heightForWidth(w);
98 return layout_item->sizeHint().y();
101 //----------------------------------------------------------------------------
102 int Layout::ItemData::mhfw(int w) const
105 return layout_item->minimumHeightForWidth(w);
107 return layout_item->minimumSize().y();
110 //----------------------------------------------------------------------------
111 void Layout::safeAdd(int& a, int b)
113 if( SGLimits<int>::max() - b < a )
114 a = SGLimits<int>::max();
119 //----------------------------------------------------------------------------
120 void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
122 const int num_children = static_cast<int>(items.size());
123 _num_not_done = num_children;
127 "Layout::distribute(" << num_children << " items)" );
129 if( space.size < space.min_size )
132 SG_LOG( SG_GUI, SG_WARN, "Layout: not enough size (not implemented)");
134 else if( space.size < space.max_size )
139 bool less_then_hint = space.size < space.size_hint;
141 // Give min_size/size_hint to all items
142 _space_left = space.size
143 - (less_then_hint ? space.min_size : space.size_hint);
144 for(int i = 0; i < num_children; ++i)
146 ItemData& d = items[i];
147 d.size = less_then_hint ? d.min_size : d.size_hint;
148 d.padding = d.padding_orig;
149 d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
154 i << ") initial=" << d.size
155 << ", min=" << d.min_size
156 << ", hint=" << d.size_hint
157 << ", max=" << d.max_size
168 _sum_stretch += d.stretch;
169 _space_stretch += d.size;
173 // Distribute remaining space to increase the size of each item up to its
174 // size_hint/max_size
175 while( _space_left > 0 )
177 if( _num_not_done <= 0 )
179 SG_LOG(SG_GUI, SG_WARN, "space left, but no more items?");
183 int space_per_element = std::max(1, _space_left / _num_not_done);
185 SG_LOG(SG_GUI, SG_DEBUG, "space/element=" << space_per_element);
187 for(int i = 0; i < num_children; ++i)
189 ItemData& d = items[i];
194 i << ") left=" << _space_left
195 << ", not_done=" << _num_not_done
196 << ", sum=" << _sum_stretch
197 << ", stretch=" << _space_stretch
198 << ", stretch/unit=" << _space_stretch / std::max(1, _sum_stretch)
204 if( _sum_stretch > 0 && d.stretch <= 0 )
209 int max_size = less_then_hint ? d.size_hint : d.max_size;
211 if( _sum_stretch > 0 )
213 target_size = (d.stretch * (_space_left + _space_stretch))
216 // Item would be smaller than minimum size or larger than maximum
217 // size, so just keep bounded size and ignore stretch factor
218 if( target_size <= d.size || target_size >= max_size )
221 _sum_stretch -= d.stretch;
222 _space_stretch -= d.size;
224 if( target_size >= max_size )
225 target_size = max_size;
227 target_size = d.size;
230 _space_stretch += target_size - d.size;
234 // Give space evenly to all remaining elements in this round
235 target_size = d.size + std::min(_space_left, space_per_element);
237 if( target_size >= max_size )
240 target_size = max_size;
244 int old_size = d.size;
245 d.size = target_size;
246 _space_left -= d.size - old_size;
253 if( _sum_stretch <= 0 && d.stretch > 0 )
254 // Distribute remaining space evenly to all non-stretchable items
263 _space_left = space.size - space.max_size;
264 for(int i = 0; i < num_children; ++i)
266 ItemData& d = items[i];
269 // Add superfluous space as padding
270 d.padding = d.padding_orig + _space_left
271 // Padding after last child...
272 / (_num_not_done + 1);
274 _space_left -= d.padding - d.padding_orig;
279 SG_LOG(SG_GUI, SG_DEBUG, "distribute:");
280 for(int i = 0; i < num_children; ++i)
282 ItemData const& d = items[i];
285 i << ") pad=" << d.padding
286 << ", size = " << d.size );
290 } // namespace canvas
291 } // namespace simgear