canvas::BoxLayout: add custom additional whitespace (spacer/stretch)
This commit is contained in:
parent
c54e3f8101
commit
e508ff724c
@ -17,6 +17,7 @@
|
||||
// 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
|
||||
@ -39,6 +40,24 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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;
|
||||
@ -47,11 +66,31 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
@ -90,24 +129,20 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -119,6 +154,12 @@ namespace canvas
|
||||
_layout_items[i].layout_item->setCanvas(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool BoxLayout::horiz() const
|
||||
{
|
||||
return (_direction == LeftToRight) || (_direction == RightToLeft);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void BoxLayout::updateSizeHints() const
|
||||
{
|
||||
@ -140,15 +181,19 @@ namespace canvas
|
||||
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);
|
||||
@ -160,7 +205,7 @@ namespace canvas
|
||||
(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)() );
|
||||
}
|
||||
|
||||
@ -216,14 +261,16 @@ namespace canvas
|
||||
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,
|
||||
@ -242,7 +289,7 @@ namespace canvas
|
||||
(size.*_get_fixed_coord)()
|
||||
));
|
||||
|
||||
if( !_reverse )
|
||||
if( !reverse )
|
||||
cur_pos.x() += data.size;
|
||||
cur_pos.y() -= offset_fixed;
|
||||
}
|
||||
|
@ -45,6 +45,16 @@ namespace canvas
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -63,6 +73,8 @@ namespace canvas
|
||||
|
||||
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
||||
|
||||
bool horiz() const;
|
||||
|
||||
protected:
|
||||
|
||||
typedef const int& (SGVec2i::*CoordGetter)() const;
|
||||
@ -72,7 +84,7 @@ namespace canvas
|
||||
// (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;
|
||||
|
@ -5,6 +5,7 @@ set(HEADERS
|
||||
Layout.hxx
|
||||
LayoutItem.hxx
|
||||
NasalWidget.hxx
|
||||
SpacerItem.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
@ -12,6 +13,7 @@ set(SOURCES
|
||||
Layout.cxx
|
||||
LayoutItem.cxx
|
||||
NasalWidget.cxx
|
||||
SpacerItem.cxx
|
||||
)
|
||||
|
||||
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
|
||||
|
@ -23,10 +23,15 @@ namespace simgear
|
||||
{
|
||||
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();
|
||||
}
|
||||
@ -132,19 +137,19 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
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
|
||||
|
@ -43,6 +43,8 @@ namespace canvas
|
||||
{
|
||||
public:
|
||||
|
||||
static const SGVec2i MAX_SIZE;
|
||||
|
||||
LayoutItem();
|
||||
virtual ~LayoutItem();
|
||||
|
||||
|
36
simgear/canvas/layout/SpacerItem.cxx
Normal file
36
simgear/canvas/layout/SpacerItem.cxx
Normal file
@ -0,0 +1,36 @@
|
||||
// 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
|
43
simgear/canvas/layout/SpacerItem.hxx
Normal file
43
simgear/canvas/layout/SpacerItem.hxx
Normal file
@ -0,0 +1,43 @@
|
||||
///@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_ */
|
@ -191,6 +191,42 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user