canvas::Layout: support for alignment.
Set alignment inside layouts, taking care of where excess space is distributed.
This commit is contained in:
parent
3bcd0bafd5
commit
d9b66fc0ef
@ -46,9 +46,11 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
|
void BoxLayout::addItem( const LayoutItemRef& item,
|
||||||
|
int stretch,
|
||||||
|
uint8_t alignment )
|
||||||
{
|
{
|
||||||
insertItem(-1, item, stretch);
|
insertItem(-1, item, stretch, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -64,12 +66,18 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
|
void BoxLayout::insertItem( int index,
|
||||||
|
const LayoutItemRef& item,
|
||||||
|
int stretch,
|
||||||
|
uint8_t alignment )
|
||||||
{
|
{
|
||||||
ItemData item_data = {0};
|
ItemData item_data = {0};
|
||||||
item_data.layout_item = item;
|
item_data.layout_item = item;
|
||||||
item_data.stretch = std::max(0, stretch);
|
item_data.stretch = std::max(0, stretch);
|
||||||
|
|
||||||
|
if( alignment != AlignFill )
|
||||||
|
item->setAlignment(alignment);
|
||||||
|
|
||||||
if( SGWeakReferenced::count(this) )
|
if( SGWeakReferenced::count(this) )
|
||||||
item->setParent(this);
|
item->setParent(this);
|
||||||
else
|
else
|
||||||
@ -270,6 +278,11 @@ namespace canvas
|
|||||||
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
||||||
item_data.has_hfw = item.hasHeightForWidth();
|
item_data.has_hfw = item.hasHeightForWidth();
|
||||||
|
|
||||||
|
uint8_t alignment_mask = horiz()
|
||||||
|
? AlignHorizontal_Mask
|
||||||
|
: AlignVertical_Mask;
|
||||||
|
item_data.has_align = (item.alignment() & alignment_mask) != 0;
|
||||||
|
|
||||||
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
|
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
|
||||||
{
|
{
|
||||||
if( is_first )
|
if( is_first )
|
||||||
@ -452,7 +465,10 @@ namespace canvas
|
|||||||
_layout_data.size_hint = size_hint_save;
|
_layout_data.size_hint = size_hint_save;
|
||||||
|
|
||||||
// and finally set the layouted geometry for each item
|
// and finally set the layouted geometry for each item
|
||||||
int fixed_size = (geom.size().*_get_fixed_coord)();
|
SGVec2i size( 0,
|
||||||
|
// Always assign all available space. Alignment handles final
|
||||||
|
// 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)() );
|
||||||
|
|
||||||
@ -467,16 +483,7 @@ namespace canvas
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
||||||
|
size.x() = data.size;
|
||||||
SGVec2i size(
|
|
||||||
data.size,
|
|
||||||
std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
|
|
||||||
fixed_size )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Center in fixed direction (TODO allow specifying alignment)
|
|
||||||
int offset_fixed = (fixed_size - size.y()) / 2;
|
|
||||||
cur_pos.y() += offset_fixed;
|
|
||||||
|
|
||||||
data.layout_item->setGeometry(SGRecti(
|
data.layout_item->setGeometry(SGRecti(
|
||||||
(cur_pos.*_get_layout_coord)(),
|
(cur_pos.*_get_layout_coord)(),
|
||||||
@ -487,7 +494,6 @@ namespace canvas
|
|||||||
|
|
||||||
if( !reverse )
|
if( !reverse )
|
||||||
cur_pos.x() += data.size;
|
cur_pos.x() += data.size;
|
||||||
cur_pos.y() -= offset_fixed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,13 +49,18 @@ namespace canvas
|
|||||||
|
|
||||||
virtual void addItem(const LayoutItemRef& item);
|
virtual void addItem(const LayoutItemRef& item);
|
||||||
|
|
||||||
void addItem(const LayoutItemRef& item, int stretch);
|
void addItem( const LayoutItemRef& item,
|
||||||
|
int stretch,
|
||||||
|
uint8_t alignment = 0 );
|
||||||
|
|
||||||
void addStretch(int stretch = 0);
|
void addStretch(int stretch = 0);
|
||||||
|
|
||||||
void addSpacing(int size);
|
void addSpacing(int size);
|
||||||
|
|
||||||
void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
|
void insertItem( int index,
|
||||||
|
const LayoutItemRef& item,
|
||||||
|
int stretch = 0,
|
||||||
|
uint8_t alignment = 0 );
|
||||||
|
|
||||||
void insertStretch(int index, int stretch = 0);
|
void insertStretch(int index, int stretch = 0);
|
||||||
|
|
||||||
|
@ -44,6 +44,19 @@ namespace canvas
|
|||||||
takeAt(0);
|
takeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGRecti Layout::alignmentRect(const SGRecti& geom) const
|
||||||
|
{
|
||||||
|
return alignment() == AlignFill
|
||||||
|
// Without explicit alignment (default == AlignFill) use the whole
|
||||||
|
// available space and let the layout and its items distribute the
|
||||||
|
// excess space.
|
||||||
|
? geom
|
||||||
|
|
||||||
|
// Otherwise align according to flags.
|
||||||
|
: LayoutItem::alignmentRect(geom);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Layout::ItemData::reset()
|
void Layout::ItemData::reset()
|
||||||
{
|
{
|
||||||
@ -56,6 +69,7 @@ namespace canvas
|
|||||||
size = 0;
|
size = 0;
|
||||||
stretch = 0;
|
stretch = 0;
|
||||||
visible = false;
|
visible = false;
|
||||||
|
has_align = false;
|
||||||
has_hfw = false;
|
has_hfw = false;
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
@ -78,6 +92,16 @@ namespace canvas
|
|||||||
return layout_item->minimumSize().y();
|
return layout_item->minimumSize().y();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Layout::Layout():
|
||||||
|
_num_not_done(0),
|
||||||
|
_sum_stretch(0),
|
||||||
|
_space_stretch(0),
|
||||||
|
_space_left(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Layout::contentsRectChanged(const SGRecti& rect)
|
void Layout::contentsRectChanged(const SGRecti& rect)
|
||||||
{
|
{
|
||||||
@ -238,27 +262,59 @@ namespace canvas
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_space_left = space.size - space.max_size;
|
_space_left = space.size - space.max_size;
|
||||||
|
int num_align = 0;
|
||||||
for(int i = 0; i < num_children; ++i)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
if( items[i].visible )
|
if( !items[i].visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
_num_not_done += 1;
|
_num_not_done += 1;
|
||||||
|
|
||||||
|
if( items[i].has_align )
|
||||||
|
num_align += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SG_LOG(
|
||||||
|
SG_GUI,
|
||||||
|
SG_DEBUG,
|
||||||
|
"Distributing excess space:"
|
||||||
|
" not_done=" << _num_not_done
|
||||||
|
<< ", num_align=" << num_align
|
||||||
|
<< ", space_left=" << _space_left
|
||||||
|
);
|
||||||
|
|
||||||
for(int i = 0; i < num_children; ++i)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
ItemData& d = items[i];
|
ItemData& d = items[i];
|
||||||
if( !d.visible )
|
if( !d.visible )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
d.padding = d.padding_orig;
|
||||||
d.size = d.max_size;
|
d.size = d.max_size;
|
||||||
|
|
||||||
|
int space_add = 0;
|
||||||
|
|
||||||
|
if( d.has_align )
|
||||||
|
{
|
||||||
|
// Equally distribute superfluous space and let each child items
|
||||||
|
// alignment handle the exact usage.
|
||||||
|
space_add = _space_left / num_align;
|
||||||
|
num_align -= 1;
|
||||||
|
|
||||||
|
d.size += space_add;
|
||||||
|
}
|
||||||
|
else if( num_align <= 0 )
|
||||||
|
{
|
||||||
// Add superfluous space as padding
|
// Add superfluous space as padding
|
||||||
d.padding = d.padding_orig + _space_left
|
space_add = _space_left
|
||||||
// Padding after last child...
|
// Padding after last child...
|
||||||
/ (_num_not_done + 1);
|
/ (_num_not_done + 1);
|
||||||
|
|
||||||
_space_left -= d.padding - d.padding_orig;
|
|
||||||
_num_not_done -= 1;
|
_num_not_done -= 1;
|
||||||
|
|
||||||
|
d.padding += space_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
_space_left -= space_add;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,18 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the actual geometry of this layout given the rectangle \a geom
|
||||||
|
* taking into account the alignment flags and size hints. For layouts,
|
||||||
|
* if no alignment (different to AlignFill) is set, the whole area is
|
||||||
|
* used. Excess space is distributed by the layouting algorithm and
|
||||||
|
* handled by the individual children.
|
||||||
|
*
|
||||||
|
* @param geom Area available to this layout.
|
||||||
|
* @return The resulting geometry for this layout.
|
||||||
|
*/
|
||||||
|
virtual SGRecti alignmentRect(const SGRecti& geom) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum LayoutFlags
|
enum LayoutFlags
|
||||||
{
|
{
|
||||||
@ -86,6 +98,7 @@ namespace canvas
|
|||||||
size, //!< layouted size
|
size, //!< layouted size
|
||||||
stretch; //!< stretch factor
|
stretch; //!< stretch factor
|
||||||
bool visible : 1,
|
bool visible : 1,
|
||||||
|
has_align: 1, //!< Has alignment factor set (!= AlignFill)
|
||||||
has_hfw : 1, //!< height for width
|
has_hfw : 1, //!< height for width
|
||||||
done : 1; //!< layouting done
|
done : 1; //!< layouting done
|
||||||
|
|
||||||
@ -96,6 +109,8 @@ namespace canvas
|
|||||||
int mhfw(int w) const;
|
int mhfw(int w) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
|
||||||
virtual void contentsRectChanged(const SGRecti& rect);
|
virtual void contentsRectChanged(const SGRecti& rect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +76,7 @@ namespace canvas
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
LayoutItem::LayoutItem():
|
LayoutItem::LayoutItem():
|
||||||
|
_alignment(AlignFill),
|
||||||
_flags(VISIBLE),
|
_flags(VISIBLE),
|
||||||
_size_hint(0, 0),
|
_size_hint(0, 0),
|
||||||
_min_size(0, 0),
|
_min_size(0, 0),
|
||||||
@ -184,6 +185,22 @@ namespace canvas
|
|||||||
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
|
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::setAlignment(uint8_t align)
|
||||||
|
{
|
||||||
|
if( align == _alignment )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_alignment = align;
|
||||||
|
invalidateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint8_t LayoutItem::alignment() const
|
||||||
|
{
|
||||||
|
return _alignment;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void LayoutItem::setVisible(bool visible)
|
void LayoutItem::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
@ -232,9 +249,10 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void LayoutItem::setGeometry(const SGRecti& geom)
|
void LayoutItem::setGeometry(const SGRecti& geom)
|
||||||
{
|
{
|
||||||
if( geom != _geometry )
|
SGRecti ar = alignmentRect(geom);
|
||||||
|
if( ar != _geometry )
|
||||||
{
|
{
|
||||||
_geometry = geom;
|
_geometry = ar;
|
||||||
_flags |= LAYOUT_DIRTY;
|
_flags |= LAYOUT_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +265,41 @@ namespace canvas
|
|||||||
return _geometry;
|
return _geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGRecti LayoutItem::alignmentRect(const SGRecti& geom) const
|
||||||
|
{
|
||||||
|
uint8_t halign = alignment() & AlignHorizontal_Mask,
|
||||||
|
valign = alignment() & AlignVertical_Mask;
|
||||||
|
|
||||||
|
// Size
|
||||||
|
SGVec2i size = sizeHint();
|
||||||
|
|
||||||
|
if( halign == AlignFill )
|
||||||
|
size.x() = maximumSize().x();
|
||||||
|
size.x() = std::min(size.x(), geom.width());
|
||||||
|
|
||||||
|
if( valign == AlignFill )
|
||||||
|
size.y() = maximumSize().y();
|
||||||
|
else if( hasHeightForWidth() )
|
||||||
|
size.y() = heightForWidth(size.x());
|
||||||
|
size.y() = std::min(size.y(), geom.height());
|
||||||
|
|
||||||
|
// Position
|
||||||
|
SGVec2i pos = geom.pos();
|
||||||
|
|
||||||
|
if( halign & AlignRight )
|
||||||
|
pos.x() += geom.width() - size.x();
|
||||||
|
else if( !(halign & AlignLeft) )
|
||||||
|
pos.x() += (geom.width() - size.x()) / 2;
|
||||||
|
|
||||||
|
if( valign & AlignBottom )
|
||||||
|
pos.y() += geom.height() - size.y();
|
||||||
|
else if( !(valign & AlignTop) )
|
||||||
|
pos.y() += (geom.height() - size.y()) / 2;
|
||||||
|
|
||||||
|
return SGRecti(pos, pos + size);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,34 @@ namespace canvas
|
|||||||
bool isNull() const;
|
bool isNull() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags for LayoutItem alignment inside Layouts.
|
||||||
|
*
|
||||||
|
* @note You can only use one horizontal and one vertical flag at the same.
|
||||||
|
*/
|
||||||
|
enum AlignmentFlag
|
||||||
|
{
|
||||||
|
AlignFill = 0, //!< Use all available space
|
||||||
|
|
||||||
|
AlignLeft = 0x01, //!< Align with left edge
|
||||||
|
AlignRight = 0x02, //!< Align with right edge
|
||||||
|
AlignHCenter = 0x04, //!< Center horizontally in available space
|
||||||
|
|
||||||
|
AlignTop = 0x20, //!< Align with top edge
|
||||||
|
AlignBottom = 0x40, //!< Align with bottom edge
|
||||||
|
AlignVCenter = 0x80, //!< Center vertically in available space
|
||||||
|
|
||||||
|
AlignCenter = AlignVCenter //!< Center both vertically and horizontally
|
||||||
|
| AlignHCenter,
|
||||||
|
|
||||||
|
AlignHorizontal_Mask = AlignLeft
|
||||||
|
| AlignRight
|
||||||
|
| AlignHCenter,
|
||||||
|
AlignVertical_Mask = AlignTop
|
||||||
|
| AlignBottom
|
||||||
|
| AlignVCenter
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all layouting elements. Specializations either implement a
|
* Base class for all layouting elements. Specializations either implement a
|
||||||
* layouting algorithm or a widget.
|
* layouting algorithm or a widget.
|
||||||
@ -186,6 +214,22 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
int minimumHeightForWidth(int w) const;
|
int minimumHeightForWidth(int w) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set alignment of item within @link{Layout Layouts}.
|
||||||
|
*
|
||||||
|
* @param alignment Bitwise combination of vertical and horizontal
|
||||||
|
* alignment flags.
|
||||||
|
* @see AlignmentFlag
|
||||||
|
*/
|
||||||
|
void setAlignment(uint8_t alignment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all alignment flags.
|
||||||
|
*
|
||||||
|
* @see AlignmentFlag
|
||||||
|
*/
|
||||||
|
uint8_t alignment() const;
|
||||||
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
virtual bool isVisible() const;
|
virtual bool isVisible() const;
|
||||||
|
|
||||||
@ -220,6 +264,20 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
virtual SGRecti geometry() const;
|
virtual SGRecti geometry() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the actual geometry of this item given the rectangle \a geom
|
||||||
|
* taking into account the alignment flags and size hints.
|
||||||
|
*
|
||||||
|
* @param geom Area available to this item.
|
||||||
|
* @return The resulting geometry for this item.
|
||||||
|
*
|
||||||
|
* @see setAlignment()
|
||||||
|
* @see minimumSize()
|
||||||
|
* @see maximumSize()
|
||||||
|
* @see sizeHint()
|
||||||
|
*/
|
||||||
|
virtual SGRecti alignmentRect(const SGRecti& geom) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the canvas this item is attached to.
|
* Set the canvas this item is attached to.
|
||||||
*/
|
*/
|
||||||
@ -266,6 +324,7 @@ namespace canvas
|
|||||||
|
|
||||||
SGRecti _geometry;
|
SGRecti _geometry;
|
||||||
Margins _margins;
|
Margins _margins;
|
||||||
|
uint8_t _alignment;
|
||||||
|
|
||||||
mutable uint32_t _flags;
|
mutable uint32_t _flags;
|
||||||
mutable SGVec2i _size_hint,
|
mutable SGVec2i _size_hint,
|
||||||
|
@ -110,45 +110,45 @@ typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||||
{
|
{
|
||||||
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
|
||||||
box_layout.setSpacing(5);
|
box_layout->setSpacing(5);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::BottomToTop);
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
|
BOOST_CHECK_EQUAL(box_layout->spacing(), 5);
|
||||||
|
|
||||||
box_layout.setDirection(sc::BoxLayout::LeftToRight);
|
box_layout->setDirection(sc::BoxLayout::LeftToRight);
|
||||||
box_layout.setSpacing(9);
|
box_layout->setSpacing(9);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
|
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::LeftToRight);
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
|
BOOST_CHECK_EQUAL(box_layout->spacing(), 9);
|
||||||
|
|
||||||
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(16, 16),
|
SGVec2i(16, 16),
|
||||||
SGVec2i(16, 16) ) );
|
SGVec2i(16, 16) ) );
|
||||||
box_layout.addItem(fixed_size_widget);
|
box_layout->addItem(fixed_size_widget);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(16, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(16, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(16, 16));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(16, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(16, 16));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(16, 16));
|
||||||
|
|
||||||
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(256, 64) ) );
|
SGVec2i(256, 64) ) );
|
||||||
box_layout.addItem(limited_resize_widget);
|
box_layout->addItem(limited_resize_widget);
|
||||||
|
|
||||||
// Combined sizes of both widget plus the padding between them
|
// Combined sizes of both widget plus the padding between them
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
|
||||||
|
|
||||||
// Test with different spacing/padding
|
// Test with different spacing/padding
|
||||||
box_layout.setSpacing(5);
|
box_layout->setSpacing(5);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(37, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(37, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(53, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(277, 64));
|
||||||
|
|
||||||
box_layout.setGeometry(SGRecti(0, 0, 128, 32));
|
box_layout->setGeometry(SGRecti(0, 0, 128, 32));
|
||||||
|
|
||||||
// Fixed size for first widget and remaining space goes to second widget
|
// Fixed size for first widget and remaining space goes to second widget
|
||||||
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
||||||
@ -157,12 +157,12 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
|||||||
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(128, 32) ) );
|
SGVec2i(128, 32) ) );
|
||||||
box_layout.addItem(stretch_widget, 1);
|
box_layout->addItem(stretch_widget, 1);
|
||||||
box_layout.update();
|
box_layout->update();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
|
||||||
|
|
||||||
// Due to the stretch factor only the last widget gets additional space. All
|
// Due to the stretch factor only the last widget gets additional space. All
|
||||||
// other widgets get the preferred size.
|
// other widgets get the preferred size.
|
||||||
@ -172,63 +172,101 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
|||||||
|
|
||||||
// Test stretch factor
|
// Test stretch factor
|
||||||
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
||||||
sc::BoxLayout box_layout_stretch(sc::BoxLayout::LeftToRight);
|
sc::BoxLayoutRef box_layout_stretch(
|
||||||
|
new sc::BoxLayout(sc::BoxLayout::LeftToRight)
|
||||||
|
);
|
||||||
|
|
||||||
box_layout_stretch.addItem(stretch_widget, 1);
|
box_layout_stretch->addItem(stretch_widget, 1);
|
||||||
box_layout_stretch.addItem(fast_stretch, 2);
|
box_layout_stretch->addItem(fast_stretch, 2);
|
||||||
|
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,128,32));
|
box_layout_stretch->setGeometry(SGRecti(0,0,128,32));
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
|
||||||
|
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,256,32));
|
box_layout_stretch->setGeometry(SGRecti(0,0,256,32));
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
||||||
|
|
||||||
// Test superflous space to padding
|
// Test superflous space to padding
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,512,32));
|
box_layout_stretch->setGeometry(SGRecti(0,0,512,32));
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
||||||
|
|
||||||
|
// ...and now with alignment
|
||||||
|
//
|
||||||
|
// All widgets without alignment get their maximum space and the remaining
|
||||||
|
// space is equally distributed to the remaining items. All items with
|
||||||
|
// alignment are set to their size hint and positioned according to their
|
||||||
|
// alignment.
|
||||||
|
|
||||||
|
// Left widget: size hint and positioned on the left
|
||||||
|
// Right widget: maximum size and positioned on the right
|
||||||
|
stretch_widget->setAlignment(sc::AlignLeft);
|
||||||
|
box_layout_stretch->update();
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
|
||||||
|
|
||||||
|
// Left widget: align right
|
||||||
|
stretch_widget->setAlignment(sc::AlignRight);
|
||||||
|
box_layout_stretch->update();
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(347, 0, 32, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
|
||||||
|
|
||||||
|
// Left widget: size hint and positioned on the right
|
||||||
|
// Right widget: size hint and positioned on the left of the right half
|
||||||
|
fast_stretch->setAlignment(sc::AlignLeft);
|
||||||
|
box_layout_stretch->update();
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(221, 0, 32, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 0, 32, 32));
|
||||||
|
|
||||||
|
// Also check vertical alignment
|
||||||
|
stretch_widget->setAlignment(sc::AlignLeft | sc::AlignTop);
|
||||||
|
fast_stretch->setAlignment(sc::AlignLeft | sc::AlignBottom);
|
||||||
|
box_layout_stretch->setGeometry(SGRecti(0,0,512,64));
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 32, 32, 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
// Test more space then preferred, but less than maximum
|
// Test more space then preferred, but less than maximum
|
||||||
|
BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
|
||||||
{
|
{
|
||||||
sc::HBoxLayout hbox;
|
sc::BoxLayoutRef hbox(new sc::HBoxLayout());
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(9999, 32) ) ),
|
SGVec2i(9999, 32) ) ),
|
||||||
w2( new TestWidget(*w1) );
|
w2( new TestWidget(*w1) );
|
||||||
|
|
||||||
hbox.addItem(w1);
|
hbox->addItem(w1);
|
||||||
hbox.addItem(w2);
|
hbox->addItem(w2);
|
||||||
|
|
||||||
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
|
hbox->setGeometry( SGRecti(0, 0, 256, 32) );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||||
|
|
||||||
hbox.setStretch(0, 1);
|
hbox->setStretch(0, 1);
|
||||||
hbox.setStretch(1, 1);
|
hbox->setStretch(1, 1);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
BOOST_CHECK_EQUAL(hbox->stretch(0), 1);
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
BOOST_CHECK_EQUAL(hbox->stretch(1), 1);
|
||||||
|
|
||||||
hbox.update();
|
hbox->update();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
||||||
|
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w1, 2) );
|
BOOST_REQUIRE( hbox->setStretchFactor(w1, 2) );
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w2, 3) );
|
BOOST_REQUIRE( hbox->setStretchFactor(w2, 3) );
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 2);
|
BOOST_CHECK_EQUAL(hbox->stretch(0), 2);
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 3);
|
BOOST_CHECK_EQUAL(hbox->stretch(1), 3);
|
||||||
|
|
||||||
hbox.removeItem(w1);
|
hbox->removeItem(w1);
|
||||||
|
|
||||||
BOOST_CHECK( !hbox.setStretchFactor(w1, 0) );
|
BOOST_CHECK( !hbox->setStretchFactor(w1, 0) );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -452,6 +490,7 @@ BOOST_AUTO_TEST_CASE( boxlayout_contents_margins )
|
|||||||
|
|
||||||
hbox->setGeometry(SGRecti(0, 0, 30, 40));
|
hbox->setGeometry(SGRecti(0, 0, 30, 40));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
|
||||||
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
|
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
|
||||||
|
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
@ -587,6 +626,52 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
|
|||||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
|
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( item_alignment_rect )
|
||||||
|
{
|
||||||
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(32, 32) ) );
|
||||||
|
|
||||||
|
const SGRecti r(10, 10, 64, 64);
|
||||||
|
|
||||||
|
// Default: AlignFill -> fill up to maximum size
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), r);
|
||||||
|
|
||||||
|
// Horizontal
|
||||||
|
|
||||||
|
// AlignLeft -> width from size hint, positioned on the left
|
||||||
|
w1->setAlignment(sc::AlignLeft);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 32, 64));
|
||||||
|
|
||||||
|
// AlignRight -> width from size hint, positioned on the left
|
||||||
|
w1->setAlignment(sc::AlignRight);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(42, 10, 32, 64));
|
||||||
|
|
||||||
|
// AlignHCenter -> width from size hint, positioned in the center
|
||||||
|
w1->setAlignment(sc::AlignHCenter);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 10, 32, 64));
|
||||||
|
|
||||||
|
|
||||||
|
// Vertical
|
||||||
|
|
||||||
|
// AlignTop -> height from size hint, positioned on the top
|
||||||
|
w1->setAlignment(sc::AlignTop);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 64, 32));
|
||||||
|
|
||||||
|
// AlignBottom -> height from size hint, positioned on the bottom
|
||||||
|
w1->setAlignment(sc::AlignBottom);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 42, 64, 32));
|
||||||
|
|
||||||
|
// AlignVCenter -> height from size hint, positioned in the center
|
||||||
|
w1->setAlignment(sc::AlignVCenter);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 26, 64, 32));
|
||||||
|
|
||||||
|
|
||||||
|
// Vertical + Horizontal
|
||||||
|
w1->setAlignment(sc::AlignCenter);
|
||||||
|
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 26, 32, 32));
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// TODO extend to_nasal_helper for automatic argument conversion
|
// TODO extend to_nasal_helper for automatic argument conversion
|
||||||
static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
|
static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
|
||||||
|
Loading…
Reference in New Issue
Block a user