1 // Align items horizontally or vertically in a box
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
19 #include "BoxLayout.hxx"
20 #include <simgear/canvas/Canvas.hxx>
27 //----------------------------------------------------------------------------
28 BoxLayout::BoxLayout(Direction dir):
34 //----------------------------------------------------------------------------
35 void BoxLayout::addItem(const LayoutItemRef& item)
37 return addItem(item, 0);
40 //----------------------------------------------------------------------------
41 void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
43 ItemData item_data = {0};
44 item_data.layout_item = item;
45 item_data.stretch = std::max(0, stretch);
47 item->setCanvas(_canvas);
48 item->setParent(this);
50 _layout_items.push_back(item_data);
55 //----------------------------------------------------------------------------
56 void BoxLayout::setStretch(size_t index, int stretch)
58 if( index >= _layout_items.size() )
61 _layout_items.at(index).stretch = std::max(0, stretch);
65 //----------------------------------------------------------------------------
66 int BoxLayout::stretch(size_t index) const
68 if( index >= _layout_items.size() )
71 return _layout_items.at(index).stretch;
74 //----------------------------------------------------------------------------
75 void BoxLayout::setSpacing(int spacing)
77 if( spacing == _padding )
84 //----------------------------------------------------------------------------
85 int BoxLayout::spacing() const
90 //----------------------------------------------------------------------------
91 void BoxLayout::setDirection(Direction dir)
93 _get_layout_coord = &SGVec2i::x;
94 _get_fixed_coord = &SGVec2i::y;
96 if( dir == TopToBottom || dir == BottomToTop )
97 std::swap(_get_layout_coord, _get_fixed_coord);
99 _reverse = (dir == RightToLeft || dir == BottomToTop );
104 //----------------------------------------------------------------------------
105 BoxLayout::Direction BoxLayout::direction() const
107 if( _get_layout_coord == static_cast<CoordGetter>(&SGVec2i::x) )
108 return _reverse ? RightToLeft : LeftToRight;
110 return _reverse ? BottomToTop : TopToBottom;
113 //----------------------------------------------------------------------------
114 void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
118 for(size_t i = 0; i < _layout_items.size(); ++i)
119 _layout_items[i].layout_item->setCanvas(canvas);
122 //----------------------------------------------------------------------------
123 void BoxLayout::updateSizeHints() const
125 SGVec2i min_size(0, 0),
129 _layout_data.reset();
130 bool is_first = true;
132 for(size_t i = 0; i < _layout_items.size(); ++i)
134 // TODO check visible
136 ItemData& item_data = _layout_items[i];
137 LayoutItem const& item = *item_data.layout_item;
139 item_data.min_size = (item.minimumSize().*_get_layout_coord)();
140 item_data.max_size = (item.maximumSize().*_get_layout_coord)();
141 item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
145 item_data.padding_orig = 0;
149 item_data.padding_orig = _padding;
151 _layout_data.padding += item_data.padding_orig;
153 // Add sizes of all children in layout direction
154 safeAdd(min_size.x(), item_data.min_size);
155 safeAdd(max_size.x(), item_data.max_size);
156 safeAdd(size_hint.x(), item_data.size_hint);
158 // Take maximum in fixed (non-layouted) direction
159 min_size.y() = std::max( min_size.y(),
160 (item.minimumSize().*_get_fixed_coord)() );
161 max_size.y() = std::max( max_size.y(),
162 (item.maximumSize().*_get_fixed_coord)() );
163 size_hint.y() = std::max( min_size.y(),
164 (item.sizeHint().*_get_fixed_coord)() );
167 safeAdd(min_size.x(), _layout_data.padding);
168 safeAdd(max_size.x(), _layout_data.padding);
169 safeAdd(size_hint.x(), _layout_data.padding);
171 _layout_data.min_size = min_size.x();
172 _layout_data.max_size = max_size.x();
173 _layout_data.size_hint = size_hint.x();
175 _min_size.x() = (min_size.*_get_layout_coord)();
176 _max_size.x() = (max_size.*_get_layout_coord)();
177 _size_hint.x() = (size_hint.*_get_layout_coord)();
179 _min_size.y() = (min_size.*_get_fixed_coord)();
180 _max_size.y() = (max_size.*_get_fixed_coord)();
181 _size_hint.y() = (size_hint.*_get_fixed_coord)();
183 _flags &= ~SIZE_INFO_DIRTY;
186 //----------------------------------------------------------------------------
187 SGVec2i BoxLayout::sizeHintImpl() const
193 //----------------------------------------------------------------------------
194 SGVec2i BoxLayout::minimumSizeImpl() const
200 //----------------------------------------------------------------------------
201 SGVec2i BoxLayout::maximumSizeImpl() const
207 //----------------------------------------------------------------------------
208 void BoxLayout::doLayout(const SGRecti& geom)
210 if( _flags & SIZE_INFO_DIRTY )
213 _layout_data.size = (geom.size().*_get_layout_coord)();
214 distribute(_layout_items, _layout_data);
216 int fixed_size = (geom.size().*_get_fixed_coord)();
217 SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
218 (geom.pos().*_get_fixed_coord)() );
220 cur_pos.x() += (geom.size().*_get_layout_coord)();
222 // TODO handle reverse layouting (rtl/btt)
223 for(size_t i = 0; i < _layout_items.size(); ++i)
225 ItemData const& data = _layout_items[i];
226 cur_pos.x() += _reverse ? -data.padding - data.size : data.padding;
230 std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
234 // Center in fixed direction (TODO allow specifying alignment)
235 int offset_fixed = (fixed_size - size.y()) / 2;
236 cur_pos.y() += offset_fixed;
238 data.layout_item->setGeometry(SGRecti(
239 (cur_pos.*_get_layout_coord)(),
240 (cur_pos.*_get_fixed_coord)(),
241 (size.*_get_layout_coord)(),
242 (size.*_get_fixed_coord)()
246 cur_pos.x() += data.size;
247 cur_pos.y() -= offset_fixed;
251 //----------------------------------------------------------------------------
252 HBoxLayout::HBoxLayout():
253 BoxLayout(LeftToRight)
258 //----------------------------------------------------------------------------
259 VBoxLayout::VBoxLayout():
260 BoxLayout(TopToBottom)
265 } // namespace canvas
266 } // namespace simgear