// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "BoxLayout.hxx"
+#include "SpacerItem.hxx"
#include <simgear/canvas/Canvas.hxx>
namespace simgear
//----------------------------------------------------------------------------
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
+ {
+ insertItem(-1, item, stretch);
+ }
+
+ //----------------------------------------------------------------------------
+ void BoxLayout::addStretch(int stretch)
+ {
+ insertStretch(-1, stretch);
+ }
+
+ //----------------------------------------------------------------------------
+ void BoxLayout::addSpacing(int size)
+ {
+ insertSpacing(-1, size);
+ }
+
+ //----------------------------------------------------------------------------
+ void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
{
ItemData item_data = {0};
item_data.layout_item = item;
item->setCanvas(_canvas);
item->setParent(this);
- _layout_items.push_back(item_data);
+ if( index < 0 )
+ _layout_items.push_back(item_data);
+ else
+ _layout_items.insert(_layout_items.begin() + index, item_data);
invalidate();
}
+ //----------------------------------------------------------------------------
+ void BoxLayout::insertStretch(int index, int stretch)
+ {
+ insertItem(index, LayoutItemRef(new SpacerItem()), stretch);
+ }
+
+ //----------------------------------------------------------------------------
+ void BoxLayout::insertSpacing(int index, int size)
+ {
+ SGVec2i size_hint = horiz()
+ ? SGVec2i(size, 0)
+ : SGVec2i(0, size),
+ max_size = size_hint;
+
+ insertItem(index, LayoutItemRef(new SpacerItem(size_hint, max_size)));
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::setStretch(size_t index, int stretch)
{
//----------------------------------------------------------------------------
void BoxLayout::setDirection(Direction dir)
{
+ _direction = dir;
_get_layout_coord = &SGVec2i::x;
_get_fixed_coord = &SGVec2i::y;
- if( dir == TopToBottom || dir == BottomToTop )
+ if( !horiz() )
std::swap(_get_layout_coord, _get_fixed_coord);
- _reverse = (dir == RightToLeft || dir == BottomToTop );
-
invalidate();
}
//----------------------------------------------------------------------------
BoxLayout::Direction BoxLayout::direction() const
{
- if( _get_layout_coord == static_cast<CoordGetter>(&SGVec2i::x) )
- return _reverse ? RightToLeft : LeftToRight;
- else
- return _reverse ? BottomToTop : TopToBottom;
+ return _direction;
}
//----------------------------------------------------------------------------
_layout_items[i].layout_item->setCanvas(canvas);
}
+ //----------------------------------------------------------------------------
+ bool BoxLayout::horiz() const
+ {
+ return (_direction == LeftToRight) || (_direction == RightToLeft);
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::updateSizeHints() const
{
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
- if( is_first )
+ if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
{
- item_data.padding_orig = 0;
- is_first = false;
+ if( is_first )
+ {
+ item_data.padding_orig = 0;
+ is_first = false;
+ }
+ else
+ {
+ item_data.padding_orig = _padding;
+ _layout_data.padding += item_data.padding_orig;
+ }
}
- else
- item_data.padding_orig = _padding;
-
- _layout_data.padding += item_data.padding_orig;
// Add sizes of all children in layout direction
safeAdd(min_size.x(), item_data.min_size);
(item.minimumSize().*_get_fixed_coord)() );
max_size.y() = std::max( max_size.y(),
(item.maximumSize().*_get_fixed_coord)() );
- size_hint.y() = std::max( min_size.y(),
+ size_hint.y() = std::max( size_hint.y(),
(item.sizeHint().*_get_fixed_coord)() );
}
int fixed_size = (geom.size().*_get_fixed_coord)();
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
(geom.pos().*_get_fixed_coord)() );
- if( _reverse )
+
+ bool reverse = (_direction == RightToLeft) || (_direction == BottomToTop);
+ if( reverse )
cur_pos.x() += (geom.size().*_get_layout_coord)();
// TODO handle reverse layouting (rtl/btt)
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData const& data = _layout_items[i];
- cur_pos.x() += _reverse ? -data.padding - data.size : data.padding;
+ cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
SGVec2i size(
data.size,
(size.*_get_fixed_coord)()
));
- if( !_reverse )
+ if( !reverse )
cur_pos.x() += data.size;
cur_pos.y() -= offset_fixed;
}
void addItem(const LayoutItemRef& item, int stretch);
+ void addStretch(int stretch = 0);
+
+ void addSpacing(int size);
+
+ void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
+
+ void insertStretch(int index, int stretch = 0);
+
+ void insertSpacing(int index, int size);
+
/**
* Set the stretch factor of the item at position @a index to @a stretch.
*/
virtual void setCanvas(const CanvasWeakPtr& canvas);
+ bool horiz() const;
+
protected:
typedef const int& (SGVec2i::*CoordGetter)() const;
// (fixed) direction
int _padding;
- bool _reverse; //<! if true, right-to-left/bottom-to-top layouting
+ Direction _direction;
mutable std::vector<ItemData> _layout_items;
mutable ItemData _layout_data;
Layout.hxx
LayoutItem.hxx
NasalWidget.hxx
+ SpacerItem.hxx
)
set(SOURCES
Layout.cxx
LayoutItem.cxx
NasalWidget.cxx
+ SpacerItem.cxx
)
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
{
namespace canvas
{
+ const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
+ SGLimits<int>::max() );
//----------------------------------------------------------------------------
LayoutItem::LayoutItem():
- _flags(0)
+ _flags(0),
+ _size_hint(16, 16),
+ _min_size(0, 0),
+ _max_size(MAX_SIZE)
{
invalidate();
}
//----------------------------------------------------------------------------
SGVec2i LayoutItem::sizeHintImpl() const
{
- return SGVec2i(16, 16);
+ return _size_hint;
}
//----------------------------------------------------------------------------
SGVec2i LayoutItem::minimumSizeImpl() const
{
- return SGVec2i(0, 0);
+ return _min_size;
}
//----------------------------------------------------------------------------
SGVec2i LayoutItem::maximumSizeImpl() const
{
- return SGVec2i(SGLimits<int>::max(), SGLimits<int>::max());
+ return _max_size;
}
} // namespace canvas
{
public:
+ static const SGVec2i MAX_SIZE;
+
LayoutItem();
virtual ~LayoutItem();
--- /dev/null
+// Element providing blank space in a layout.
+//
+// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "SpacerItem.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+ //----------------------------------------------------------------------------
+ SpacerItem::SpacerItem( const SGVec2i& size,
+ const SGVec2i& max_size )
+ {
+ _size_hint = size;
+ _min_size = size;
+ _max_size = max_size;
+ }
+
+} // namespace canvas
+} // namespace simgear
--- /dev/null
+///@file Element providing blank space in a layout.
+//
+// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef SG_CANVAS_SPACER_ITEM_HXX_
+#define SG_CANVAS_SPACER_ITEM_HXX_
+
+#include "LayoutItem.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+ /**
+ * Element for providing blank space in a layout.
+ */
+ class SpacerItem:
+ public LayoutItem
+ {
+ public:
+ SpacerItem( const SGVec2i& size = SGVec2i(0, 0),
+ const SGVec2i& max_size = MAX_SIZE );
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* SG_CANVAS_SPACER_ITEM_HXX_ */
}
}
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( spacer_layouting )
+{
+ sc::HBoxLayout hbox;
+ TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
+ SGVec2i(32, 32),
+ SGVec2i(9999, 9999) ) ),
+ w2( new TestWidget(*w1) );
+
+ hbox.addItem(w1);
+ hbox.addItem(w2);
+ hbox.addStretch(1);
+
+ BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(37, 16));
+ BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(69, 32));
+ BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+
+ hbox.setGeometry(SGRecti(0, 0, 256, 40));
+
+ BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 40));
+ BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(37, 0, 32, 40));
+
+ // now center with increased spacing between both widgets
+ hbox.insertStretch(0, 1);
+ hbox.insertSpacing(2, 10);
+
+ BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(47, 16));
+ BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(79, 32));
+ BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+
+ hbox.update();
+
+ BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(88, 0, 32, 40));
+ BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(135, 0, 32, 40));
+}
+
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( vertical_layout)
{