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
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "BoxLayout.hxx"
|
#include "BoxLayout.hxx"
|
||||||
|
#include "SpacerItem.hxx"
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@ -39,6 +40,24 @@ namespace canvas
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
|
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};
|
ItemData item_data = {0};
|
||||||
item_data.layout_item = item;
|
item_data.layout_item = item;
|
||||||
@ -47,11 +66,31 @@ namespace canvas
|
|||||||
item->setCanvas(_canvas);
|
item->setCanvas(_canvas);
|
||||||
item->setParent(this);
|
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();
|
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::setStretch(size_t index, int stretch)
|
||||||
{
|
{
|
||||||
@ -90,24 +129,20 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void BoxLayout::setDirection(Direction dir)
|
void BoxLayout::setDirection(Direction dir)
|
||||||
{
|
{
|
||||||
|
_direction = dir;
|
||||||
_get_layout_coord = &SGVec2i::x;
|
_get_layout_coord = &SGVec2i::x;
|
||||||
_get_fixed_coord = &SGVec2i::y;
|
_get_fixed_coord = &SGVec2i::y;
|
||||||
|
|
||||||
if( dir == TopToBottom || dir == BottomToTop )
|
if( !horiz() )
|
||||||
std::swap(_get_layout_coord, _get_fixed_coord);
|
std::swap(_get_layout_coord, _get_fixed_coord);
|
||||||
|
|
||||||
_reverse = (dir == RightToLeft || dir == BottomToTop );
|
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
BoxLayout::Direction BoxLayout::direction() const
|
BoxLayout::Direction BoxLayout::direction() const
|
||||||
{
|
{
|
||||||
if( _get_layout_coord == static_cast<CoordGetter>(&SGVec2i::x) )
|
return _direction;
|
||||||
return _reverse ? RightToLeft : LeftToRight;
|
|
||||||
else
|
|
||||||
return _reverse ? BottomToTop : TopToBottom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -119,6 +154,12 @@ namespace canvas
|
|||||||
_layout_items[i].layout_item->setCanvas(canvas);
|
_layout_items[i].layout_item->setCanvas(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool BoxLayout::horiz() const
|
||||||
|
{
|
||||||
|
return (_direction == LeftToRight) || (_direction == RightToLeft);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void BoxLayout::updateSizeHints() const
|
void BoxLayout::updateSizeHints() const
|
||||||
{
|
{
|
||||||
@ -140,15 +181,19 @@ namespace canvas
|
|||||||
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
||||||
item_data.size_hint = (item.sizeHint().*_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;
|
if( is_first )
|
||||||
is_first = false;
|
{
|
||||||
|
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
|
// Add sizes of all children in layout direction
|
||||||
safeAdd(min_size.x(), item_data.min_size);
|
safeAdd(min_size.x(), item_data.min_size);
|
||||||
@ -160,7 +205,7 @@ namespace canvas
|
|||||||
(item.minimumSize().*_get_fixed_coord)() );
|
(item.minimumSize().*_get_fixed_coord)() );
|
||||||
max_size.y() = std::max( max_size.y(),
|
max_size.y() = std::max( max_size.y(),
|
||||||
(item.maximumSize().*_get_fixed_coord)() );
|
(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)() );
|
(item.sizeHint().*_get_fixed_coord)() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,14 +261,16 @@ namespace canvas
|
|||||||
int fixed_size = (geom.size().*_get_fixed_coord)();
|
int fixed_size = (geom.size().*_get_fixed_coord)();
|
||||||
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
||||||
(geom.pos().*_get_fixed_coord)() );
|
(geom.pos().*_get_fixed_coord)() );
|
||||||
if( _reverse )
|
|
||||||
|
bool reverse = (_direction == RightToLeft) || (_direction == BottomToTop);
|
||||||
|
if( reverse )
|
||||||
cur_pos.x() += (geom.size().*_get_layout_coord)();
|
cur_pos.x() += (geom.size().*_get_layout_coord)();
|
||||||
|
|
||||||
// TODO handle reverse layouting (rtl/btt)
|
// TODO handle reverse layouting (rtl/btt)
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
ItemData const& data = _layout_items[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(
|
SGVec2i size(
|
||||||
data.size,
|
data.size,
|
||||||
@ -242,7 +289,7 @@ namespace canvas
|
|||||||
(size.*_get_fixed_coord)()
|
(size.*_get_fixed_coord)()
|
||||||
));
|
));
|
||||||
|
|
||||||
if( !_reverse )
|
if( !reverse )
|
||||||
cur_pos.x() += data.size;
|
cur_pos.x() += data.size;
|
||||||
cur_pos.y() -= offset_fixed;
|
cur_pos.y() -= offset_fixed;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,16 @@ namespace canvas
|
|||||||
|
|
||||||
void addItem(const LayoutItemRef& item, int stretch);
|
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.
|
* 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);
|
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
||||||
|
|
||||||
|
bool horiz() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef const int& (SGVec2i::*CoordGetter)() const;
|
typedef const int& (SGVec2i::*CoordGetter)() const;
|
||||||
@ -72,7 +84,7 @@ namespace canvas
|
|||||||
// (fixed) direction
|
// (fixed) direction
|
||||||
|
|
||||||
int _padding;
|
int _padding;
|
||||||
bool _reverse; //<! if true, right-to-left/bottom-to-top layouting
|
Direction _direction;
|
||||||
|
|
||||||
mutable std::vector<ItemData> _layout_items;
|
mutable std::vector<ItemData> _layout_items;
|
||||||
mutable ItemData _layout_data;
|
mutable ItemData _layout_data;
|
||||||
|
@ -5,6 +5,7 @@ set(HEADERS
|
|||||||
Layout.hxx
|
Layout.hxx
|
||||||
LayoutItem.hxx
|
LayoutItem.hxx
|
||||||
NasalWidget.hxx
|
NasalWidget.hxx
|
||||||
|
SpacerItem.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
@ -12,6 +13,7 @@ set(SOURCES
|
|||||||
Layout.cxx
|
Layout.cxx
|
||||||
LayoutItem.cxx
|
LayoutItem.cxx
|
||||||
NasalWidget.cxx
|
NasalWidget.cxx
|
||||||
|
SpacerItem.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
|
||||||
|
@ -23,10 +23,15 @@ namespace simgear
|
|||||||
{
|
{
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
|
||||||
|
SGLimits<int>::max() );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
LayoutItem::LayoutItem():
|
LayoutItem::LayoutItem():
|
||||||
_flags(0)
|
_flags(0),
|
||||||
|
_size_hint(16, 16),
|
||||||
|
_min_size(0, 0),
|
||||||
|
_max_size(MAX_SIZE)
|
||||||
{
|
{
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@ -132,19 +137,19 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
SGVec2i LayoutItem::sizeHintImpl() const
|
SGVec2i LayoutItem::sizeHintImpl() const
|
||||||
{
|
{
|
||||||
return SGVec2i(16, 16);
|
return _size_hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
SGVec2i LayoutItem::minimumSizeImpl() const
|
SGVec2i LayoutItem::minimumSizeImpl() const
|
||||||
{
|
{
|
||||||
return SGVec2i(0, 0);
|
return _min_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
SGVec2i LayoutItem::maximumSizeImpl() const
|
SGVec2i LayoutItem::maximumSizeImpl() const
|
||||||
{
|
{
|
||||||
return SGVec2i(SGLimits<int>::max(), SGLimits<int>::max());
|
return _max_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
@ -43,6 +43,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static const SGVec2i MAX_SIZE;
|
||||||
|
|
||||||
LayoutItem();
|
LayoutItem();
|
||||||
virtual ~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)
|
BOOST_AUTO_TEST_CASE( vertical_layout)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user