1 // Basic element for layouting canvas elements
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 "LayoutItem.hxx"
20 #include <simgear/canvas/Canvas.hxx>
27 //----------------------------------------------------------------------------
28 Margins::Margins(int m):
29 l(m), t(m), r(m), b(m)
34 //----------------------------------------------------------------------------
35 Margins::Margins(int h, int v):
42 //----------------------------------------------------------------------------
43 Margins::Margins(int l, int t, int r, int b):
44 l(l), t(t), r(r), b(b)
49 //----------------------------------------------------------------------------
50 int Margins::horiz() const
55 //----------------------------------------------------------------------------
56 int Margins::vert() const
61 //----------------------------------------------------------------------------
62 SGVec2i Margins::size() const
64 return SGVec2i(horiz(), vert());
67 //----------------------------------------------------------------------------
68 bool Margins::isNull() const
70 return l == 0 && t == 0 && r == 0 && b == 0;
73 //----------------------------------------------------------------------------
74 const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
75 SGLimits<int>::max() );
77 //----------------------------------------------------------------------------
78 LayoutItem::LayoutItem():
79 _alignment(AlignFill),
88 //----------------------------------------------------------------------------
89 LayoutItem::~LayoutItem()
94 //----------------------------------------------------------------------------
95 void LayoutItem::setContentsMargins(const Margins& margins)
100 //----------------------------------------------------------------------------
101 void LayoutItem::setContentsMargins(int left, int top, int right, int bottom)
109 //----------------------------------------------------------------------------
110 void LayoutItem::setContentsMargin(int margin)
112 setContentsMargins(margin, margin, margin, margin);
115 //----------------------------------------------------------------------------
116 Margins LayoutItem::getContentsMargins() const
121 //----------------------------------------------------------------------------
122 SGRecti LayoutItem::contentsRect() const
125 _geometry.x() + _margins.l,
126 _geometry.y() + _margins.t,
127 std::max(0, _geometry.width() - _margins.horiz()),
128 std::max(0, _geometry.height() - _margins.vert())
132 //----------------------------------------------------------------------------
133 SGVec2i LayoutItem::sizeHint() const
135 if( _flags & SIZE_HINT_DIRTY )
137 _size_hint = sizeHintImpl();
138 _flags &= ~SIZE_HINT_DIRTY;
141 return addClipOverflow(_size_hint, _margins.size());
144 //----------------------------------------------------------------------------
145 SGVec2i LayoutItem::minimumSize() const
147 if( _flags & MINIMUM_SIZE_DIRTY )
149 _min_size = minimumSizeImpl();
150 _flags &= ~MINIMUM_SIZE_DIRTY;
153 return addClipOverflow(_min_size, _margins.size());
156 //----------------------------------------------------------------------------
157 SGVec2i LayoutItem::maximumSize() const
159 if( _flags & MAXIMUM_SIZE_DIRTY )
161 _max_size = maximumSizeImpl();
162 _flags &= ~MAXIMUM_SIZE_DIRTY;
165 return addClipOverflow(_max_size, _margins.size());
168 //----------------------------------------------------------------------------
169 bool LayoutItem::hasHeightForWidth() const
174 //----------------------------------------------------------------------------
175 int LayoutItem::heightForWidth(int w) const
177 int h = heightForWidthImpl(w - _margins.horiz());
178 return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
181 //------------------------------------------------------------------------------
182 int LayoutItem::minimumHeightForWidth(int w) const
184 int h = minimumHeightForWidthImpl(w - _margins.horiz());
185 return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
188 //----------------------------------------------------------------------------
189 void LayoutItem::setAlignment(uint8_t align)
191 if( align == _alignment )
198 //----------------------------------------------------------------------------
199 uint8_t LayoutItem::alignment() const
204 //----------------------------------------------------------------------------
205 void LayoutItem::setVisible(bool visible)
208 _flags &= ~EXPLICITLY_HIDDEN;
210 _flags |= EXPLICITLY_HIDDEN;
212 setVisibleInternal(visible);
215 //----------------------------------------------------------------------------
216 bool LayoutItem::isVisible() const
218 return _flags & VISIBLE;
221 //----------------------------------------------------------------------------
222 bool LayoutItem::isExplicitlyHidden() const
224 return _flags & EXPLICITLY_HIDDEN;
227 //----------------------------------------------------------------------------
228 void LayoutItem::invalidate()
230 _flags |= SIZE_INFO_DIRTY | LAYOUT_DIRTY;
234 //----------------------------------------------------------------------------
235 void LayoutItem::invalidateParent()
237 LayoutItemRef parent = _parent.lock();
239 parent->invalidate();
242 //----------------------------------------------------------------------------
243 void LayoutItem::update()
245 if( (_flags & LAYOUT_DIRTY) && isVisible() )
246 contentsRectChanged( contentsRect() );
249 //----------------------------------------------------------------------------
250 void LayoutItem::setGeometry(const SGRecti& geom)
252 SGRecti ar = alignmentRect(geom);
253 if( ar != _geometry )
256 _flags |= LAYOUT_DIRTY;
262 //----------------------------------------------------------------------------
263 SGRecti LayoutItem::geometry() const
268 //----------------------------------------------------------------------------
269 SGRecti LayoutItem::alignmentRect(const SGRecti& geom) const
271 uint8_t halign = alignment() & AlignHorizontal_Mask,
272 valign = alignment() & AlignVertical_Mask;
275 SGVec2i size = sizeHint();
277 if( halign == AlignFill )
278 size.x() = maximumSize().x();
279 size.x() = std::min(size.x(), geom.width());
281 if( valign == AlignFill )
282 size.y() = maximumSize().y();
283 else if( hasHeightForWidth() )
284 size.y() = heightForWidth(size.x());
285 size.y() = std::min(size.y(), geom.height());
288 SGVec2i pos = geom.pos();
290 if( halign & AlignRight )
291 pos.x() += geom.width() - size.x();
292 else if( !(halign & AlignLeft) )
293 pos.x() += (geom.width() - size.x()) / 2;
295 if( valign & AlignBottom )
296 pos.y() += geom.height() - size.y();
297 else if( !(valign & AlignTop) )
298 pos.y() += (geom.height() - size.y()) / 2;
300 return SGRecti(pos, pos + size);
303 //----------------------------------------------------------------------------
304 void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
309 //----------------------------------------------------------------------------
310 CanvasPtr LayoutItem::getCanvas() const
312 return _canvas.lock();
315 //----------------------------------------------------------------------------
316 void LayoutItem::setParent(const LayoutItemWeakRef& parent)
319 LayoutItemRef parent_ref = parent.lock();
322 // Only change the canvas if there is a new parent. If the item is removed
323 // keep the old canvas, as it may be used for example during the call to
325 setCanvas(parent_ref->_canvas);
327 setVisibleInternal(!parent_ref || parent_ref->isVisible());
330 //----------------------------------------------------------------------------
331 LayoutItemRef LayoutItem::getParent() const
333 return _parent.lock();
336 //----------------------------------------------------------------------------
337 SGVec2i LayoutItem::sizeHintImpl() const
342 //----------------------------------------------------------------------------
343 SGVec2i LayoutItem::minimumSizeImpl() const
348 //----------------------------------------------------------------------------
349 SGVec2i LayoutItem::maximumSizeImpl() const
354 //----------------------------------------------------------------------------
355 int LayoutItem::heightForWidthImpl(int w) const
360 //------------------------------------------------------------------------------
361 int LayoutItem::minimumHeightForWidthImpl(int w) const
363 return heightForWidth(w);
366 //----------------------------------------------------------------------------
367 void LayoutItem::setVisibleInternal(bool visible)
369 LayoutItemRef parent = getParent();
370 if( isExplicitlyHidden() || (parent && !parent->isVisible()) )
373 if( isVisible() == visible )
383 visibilityChanged(visible);
386 //----------------------------------------------------------------------------
387 void LayoutItem::callSetVisibleInternal(LayoutItem* item, bool visible)
389 item->setVisibleInternal(visible);
392 } // namespace canvas
393 } // namespace simgear