]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/layout/LayoutItem.cxx
canvas::Layout: support for contents margins.
[simgear.git] / simgear / canvas / layout / LayoutItem.cxx
1 // Basic element for layouting canvas elements
2 //
3 // Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
4 //
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.
9 //
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.
14 //
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
18
19 #include "LayoutItem.hxx"
20 #include <simgear/canvas/Canvas.hxx>
21
22 namespace simgear
23 {
24 namespace canvas
25 {
26
27   //----------------------------------------------------------------------------
28   Margins::Margins(int m):
29     l(m), t(m), r(m), b(m)
30   {
31
32   }
33
34   //----------------------------------------------------------------------------
35   Margins::Margins(int h, int v):
36     l(h), t(v),
37     r(h), b(v)
38   {
39
40   }
41
42   //----------------------------------------------------------------------------
43   Margins::Margins(int l, int t, int r, int b):
44     l(l), t(t), r(r), b(b)
45   {
46
47   }
48
49   //----------------------------------------------------------------------------
50   int Margins::horiz() const
51   {
52     return l + r;
53   }
54
55   //----------------------------------------------------------------------------
56   int Margins::vert() const
57   {
58     return t + b;
59   }
60
61   //----------------------------------------------------------------------------
62   SGVec2i Margins::size() const
63   {
64     return SGVec2i(horiz(), vert());
65   }
66
67   //----------------------------------------------------------------------------
68   bool Margins::isNull() const
69   {
70     return l == 0 && t == 0 && r == 0 && b == 0;
71   }
72
73   //----------------------------------------------------------------------------
74   const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
75                                       SGLimits<int>::max() );
76
77   //----------------------------------------------------------------------------
78   LayoutItem::LayoutItem():
79     _flags(VISIBLE),
80     _size_hint(0, 0),
81     _min_size(0, 0),
82     _max_size(MAX_SIZE)
83   {
84     invalidate();
85   }
86
87   //----------------------------------------------------------------------------
88   LayoutItem::~LayoutItem()
89   {
90
91   }
92
93   //----------------------------------------------------------------------------
94   void LayoutItem::setContentsMargins(const Margins& margins)
95   {
96     _margins = margins;
97   }
98
99   //----------------------------------------------------------------------------
100   void LayoutItem::setContentsMargins(int left, int top, int right, int bottom)
101   {
102     _margins.l = left;
103     _margins.t = top;
104     _margins.r = right;
105     _margins.b = bottom;
106   }
107
108   //----------------------------------------------------------------------------
109   void LayoutItem::setContentsMargin(int margin)
110   {
111     setContentsMargins(margin, margin, margin, margin);
112   }
113
114   //----------------------------------------------------------------------------
115   Margins LayoutItem::getContentsMargins() const
116   {
117     return _margins;
118   }
119
120   //----------------------------------------------------------------------------
121   SGRecti LayoutItem::contentsRect() const
122   {
123     return SGRecti(
124       _geometry.x() + _margins.l,
125       _geometry.y() + _margins.t,
126       std::max(0, _geometry.width() - _margins.horiz()),
127       std::max(0, _geometry.height() - _margins.vert())
128     );
129   }
130
131   //----------------------------------------------------------------------------
132   SGVec2i LayoutItem::sizeHint() const
133   {
134     if( _flags & SIZE_HINT_DIRTY )
135     {
136       _size_hint = sizeHintImpl();
137       _flags &= ~SIZE_HINT_DIRTY;
138     }
139
140     return addClipOverflow(_size_hint, _margins.size());
141   }
142
143   //----------------------------------------------------------------------------
144   SGVec2i LayoutItem::minimumSize() const
145   {
146     if( _flags & MINIMUM_SIZE_DIRTY )
147     {
148       _min_size = minimumSizeImpl();
149       _flags &= ~MINIMUM_SIZE_DIRTY;
150     }
151
152     return addClipOverflow(_min_size, _margins.size());
153   }
154
155   //----------------------------------------------------------------------------
156   SGVec2i LayoutItem::maximumSize() const
157   {
158     if( _flags & MAXIMUM_SIZE_DIRTY )
159     {
160       _max_size = maximumSizeImpl();
161       _flags &= ~MAXIMUM_SIZE_DIRTY;
162     }
163
164     return addClipOverflow(_max_size, _margins.size());
165   }
166
167   //----------------------------------------------------------------------------
168   bool LayoutItem::hasHeightForWidth() const
169   {
170     return false;
171   }
172
173   //----------------------------------------------------------------------------
174   int LayoutItem::heightForWidth(int w) const
175   {
176     int h = heightForWidthImpl(w - _margins.horiz());
177     return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
178   }
179
180   //------------------------------------------------------------------------------
181   int LayoutItem::minimumHeightForWidth(int w) const
182   {
183     int h = minimumHeightForWidthImpl(w - _margins.horiz());
184     return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
185   }
186
187   //----------------------------------------------------------------------------
188   void LayoutItem::setVisible(bool visible)
189   {
190     if( visible )
191       _flags &= ~EXPLICITLY_HIDDEN;
192     else
193       _flags |= EXPLICITLY_HIDDEN;
194
195     setVisibleInternal(visible);
196   }
197
198   //----------------------------------------------------------------------------
199   bool LayoutItem::isVisible() const
200   {
201     return _flags & VISIBLE;
202   }
203
204   //----------------------------------------------------------------------------
205   bool LayoutItem::isExplicitlyHidden() const
206   {
207     return _flags & EXPLICITLY_HIDDEN;
208   }
209
210   //----------------------------------------------------------------------------
211   void LayoutItem::invalidate()
212   {
213     _flags |= SIZE_INFO_DIRTY | LAYOUT_DIRTY;
214     invalidateParent();
215   }
216
217   //----------------------------------------------------------------------------
218   void LayoutItem::invalidateParent()
219   {
220     LayoutItemRef parent = _parent.lock();
221     if( parent )
222       parent->invalidate();
223   }
224
225   //----------------------------------------------------------------------------
226   void LayoutItem::update()
227   {
228     if( (_flags & LAYOUT_DIRTY) && isVisible() )
229       contentsRectChanged( contentsRect() );
230   }
231
232   //----------------------------------------------------------------------------
233   void LayoutItem::setGeometry(const SGRecti& geom)
234   {
235     if( geom != _geometry )
236     {
237       _geometry = geom;
238       _flags |= LAYOUT_DIRTY;
239     }
240
241     update();
242   }
243
244   //----------------------------------------------------------------------------
245   SGRecti LayoutItem::geometry() const
246   {
247     return _geometry;
248   }
249
250   //----------------------------------------------------------------------------
251   void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
252   {
253     _canvas = canvas;
254   }
255
256   //----------------------------------------------------------------------------
257   CanvasPtr LayoutItem::getCanvas() const
258   {
259     return _canvas.lock();
260   }
261
262   //----------------------------------------------------------------------------
263   void LayoutItem::setParent(const LayoutItemWeakRef& parent)
264   {
265     _parent = parent;
266     LayoutItemRef parent_ref = parent.lock();
267
268     if( parent_ref )
269       // Only change the canvas if there is a new parent. If the item is removed
270       // keep the old canvas, as it may be used for example during the call to
271       // onRemove.
272       setCanvas(parent_ref->_canvas);
273
274     setVisibleInternal(!parent_ref || parent_ref->isVisible());
275   }
276
277   //----------------------------------------------------------------------------
278   LayoutItemRef LayoutItem::getParent() const
279   {
280     return _parent.lock();
281   }
282
283   //----------------------------------------------------------------------------
284   SGVec2i LayoutItem::sizeHintImpl() const
285   {
286     return _size_hint;
287   }
288
289   //----------------------------------------------------------------------------
290   SGVec2i LayoutItem::minimumSizeImpl() const
291   {
292     return _min_size;
293   }
294
295   //----------------------------------------------------------------------------
296   SGVec2i LayoutItem::maximumSizeImpl() const
297   {
298     return _max_size;
299   }
300
301   //----------------------------------------------------------------------------
302   int LayoutItem::heightForWidthImpl(int w) const
303   {
304     return -1;
305   }
306
307   //------------------------------------------------------------------------------
308   int LayoutItem::minimumHeightForWidthImpl(int w) const
309   {
310     return heightForWidth(w);
311   }
312
313   //----------------------------------------------------------------------------
314   void LayoutItem::setVisibleInternal(bool visible)
315   {
316     LayoutItemRef parent = getParent();
317     if( isExplicitlyHidden() || (parent && !parent->isVisible()) )
318       visible = false;
319
320     if( isVisible() == visible )
321       return;
322
323     invalidateParent();
324
325     if( visible )
326       _flags |= VISIBLE;
327     else
328       _flags &= ~VISIBLE;
329
330     visibilityChanged(visible);
331   }
332
333   //----------------------------------------------------------------------------
334   void LayoutItem::callSetVisibleInternal(LayoutItem* item, bool visible)
335   {
336     item->setVisibleInternal(visible);
337   }
338
339 } // namespace canvas
340 } // namespace simgear