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};
|
||||
item_data.layout_item = item;
|
||||
item_data.stretch = std::max(0, stretch);
|
||||
|
||||
if( alignment != AlignFill )
|
||||
item->setAlignment(alignment);
|
||||
|
||||
if( SGWeakReferenced::count(this) )
|
||||
item->setParent(this);
|
||||
else
|
||||
@ -270,6 +278,11 @@ namespace canvas
|
||||
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
||||
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( is_first )
|
||||
@ -452,7 +465,10 @@ namespace canvas
|
||||
_layout_data.size_hint = size_hint_save;
|
||||
|
||||
// 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)(),
|
||||
(geom.pos().*_get_fixed_coord)() );
|
||||
|
||||
@ -467,16 +483,7 @@ namespace canvas
|
||||
continue;
|
||||
|
||||
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
||||
|
||||
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;
|
||||
size.x() = data.size;
|
||||
|
||||
data.layout_item->setGeometry(SGRecti(
|
||||
(cur_pos.*_get_layout_coord)(),
|
||||
@ -487,7 +494,6 @@ namespace canvas
|
||||
|
||||
if( !reverse )
|
||||
cur_pos.x() += data.size;
|
||||
cur_pos.y() -= offset_fixed;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,13 +49,18 @@ namespace canvas
|
||||
|
||||
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 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);
|
||||
|
||||
|
@ -44,6 +44,19 @@ namespace canvas
|
||||
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()
|
||||
{
|
||||
@ -56,6 +69,7 @@ namespace canvas
|
||||
size = 0;
|
||||
stretch = 0;
|
||||
visible = false;
|
||||
has_align = false;
|
||||
has_hfw = false;
|
||||
done = false;
|
||||
}
|
||||
@ -78,6 +92,16 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
@ -238,27 +262,59 @@ namespace canvas
|
||||
else
|
||||
{
|
||||
_space_left = space.size - space.max_size;
|
||||
int num_align = 0;
|
||||
for(int i = 0; i < num_children; ++i)
|
||||
{
|
||||
if( items[i].visible )
|
||||
if( !items[i].visible )
|
||||
continue;
|
||||
|
||||
_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)
|
||||
{
|
||||
ItemData& d = items[i];
|
||||
if( !d.visible )
|
||||
continue;
|
||||
|
||||
d.padding = d.padding_orig;
|
||||
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
|
||||
d.padding = d.padding_orig + _space_left
|
||||
space_add = _space_left
|
||||
// Padding after last child...
|
||||
/ (_num_not_done + 1);
|
||||
|
||||
_space_left -= d.padding - d.padding_orig;
|
||||
_num_not_done -= 1;
|
||||
|
||||
d.padding += space_add;
|
||||
}
|
||||
|
||||
_space_left -= space_add;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,18 @@ namespace canvas
|
||||
*/
|
||||
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:
|
||||
enum LayoutFlags
|
||||
{
|
||||
@ -86,6 +98,7 @@ namespace canvas
|
||||
size, //!< layouted size
|
||||
stretch; //!< stretch factor
|
||||
bool visible : 1,
|
||||
has_align: 1, //!< Has alignment factor set (!= AlignFill)
|
||||
has_hfw : 1, //!< height for width
|
||||
done : 1; //!< layouting done
|
||||
|
||||
@ -96,6 +109,8 @@ namespace canvas
|
||||
int mhfw(int w) const;
|
||||
};
|
||||
|
||||
Layout();
|
||||
|
||||
virtual void contentsRectChanged(const SGRecti& rect);
|
||||
|
||||
/**
|
||||
|
@ -76,6 +76,7 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
LayoutItem::LayoutItem():
|
||||
_alignment(AlignFill),
|
||||
_flags(VISIBLE),
|
||||
_size_hint(0, 0),
|
||||
_min_size(0, 0),
|
||||
@ -184,6 +185,22 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
@ -232,9 +249,10 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setGeometry(const SGRecti& geom)
|
||||
{
|
||||
if( geom != _geometry )
|
||||
SGRecti ar = alignmentRect(geom);
|
||||
if( ar != _geometry )
|
||||
{
|
||||
_geometry = geom;
|
||||
_geometry = ar;
|
||||
_flags |= LAYOUT_DIRTY;
|
||||
}
|
||||
|
||||
@ -247,6 +265,41 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
|
@ -82,6 +82,34 @@ namespace canvas
|
||||
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
|
||||
* layouting algorithm or a widget.
|
||||
@ -186,6 +214,22 @@ namespace canvas
|
||||
*/
|
||||
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 bool isVisible() const;
|
||||
|
||||
@ -220,6 +264,20 @@ namespace canvas
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -266,6 +324,7 @@ namespace canvas
|
||||
|
||||
SGRecti _geometry;
|
||||
Margins _margins;
|
||||
uint8_t _alignment;
|
||||
|
||||
mutable uint32_t _flags;
|
||||
mutable SGVec2i _size_hint,
|
||||
|
@ -110,45 +110,45 @@ typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
{
|
||||
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
||||
box_layout.setSpacing(5);
|
||||
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
|
||||
box_layout->setSpacing(5);
|
||||
|
||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
|
||||
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::BottomToTop);
|
||||
BOOST_CHECK_EQUAL(box_layout->spacing(), 5);
|
||||
|
||||
box_layout.setDirection(sc::BoxLayout::LeftToRight);
|
||||
box_layout.setSpacing(9);
|
||||
box_layout->setDirection(sc::BoxLayout::LeftToRight);
|
||||
box_layout->setSpacing(9);
|
||||
|
||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
|
||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
|
||||
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::LeftToRight);
|
||||
BOOST_CHECK_EQUAL(box_layout->spacing(), 9);
|
||||
|
||||
TestWidgetRef fixed_size_widget( new TestWidget( 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.sizeHint(), SGVec2i(16, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), 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->maximumSize(), SGVec2i(16, 16));
|
||||
|
||||
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32),
|
||||
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
|
||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
|
||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
|
||||
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
|
||||
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
|
||||
|
||||
// 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.sizeHint(), SGVec2i(53, 32));
|
||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
|
||||
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(37, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
|
||||
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
|
||||
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),
|
||||
SGVec2i(32, 32),
|
||||
SGVec2i(128, 32) ) );
|
||||
box_layout.addItem(stretch_widget, 1);
|
||||
box_layout.update();
|
||||
box_layout->addItem(stretch_widget, 1);
|
||||
box_layout->update();
|
||||
|
||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
|
||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
|
||||
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
|
||||
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
|
||||
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
|
||||
|
||||
// Due to the stretch factor only the last widget gets additional space. All
|
||||
// other widgets get the preferred size.
|
||||
@ -172,63 +172,101 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
|
||||
// Test stretch factor
|
||||
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(fast_stretch, 2);
|
||||
box_layout_stretch->addItem(stretch_widget, 1);
|
||||
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(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(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
||||
|
||||
// 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(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
|
||||
BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
|
||||
{
|
||||
sc::HBoxLayout hbox;
|
||||
sc::BoxLayoutRef hbox(new sc::HBoxLayout());
|
||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32),
|
||||
SGVec2i(9999, 32) ) ),
|
||||
w2( new TestWidget(*w1) );
|
||||
|
||||
hbox.addItem(w1);
|
||||
hbox.addItem(w2);
|
||||
hbox->addItem(w1);
|
||||
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(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||
|
||||
hbox.setStretch(0, 1);
|
||||
hbox.setStretch(1, 1);
|
||||
hbox->setStretch(0, 1);
|
||||
hbox->setStretch(1, 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
||||
BOOST_CHECK_EQUAL(hbox->stretch(0), 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(w2->geometry(), SGRecti(130, 0, 126, 32));
|
||||
|
||||
BOOST_REQUIRE( hbox.setStretchFactor(w1, 2) );
|
||||
BOOST_REQUIRE( hbox.setStretchFactor(w2, 3) );
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 2);
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 3);
|
||||
BOOST_REQUIRE( hbox->setStretchFactor(w1, 2) );
|
||||
BOOST_REQUIRE( hbox->setStretchFactor(w2, 3) );
|
||||
BOOST_CHECK_EQUAL(hbox->stretch(0), 2);
|
||||
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));
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
|
||||
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
|
||||
|
||||
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_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
|
||||
static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
|
||||
|
Loading…
Reference in New Issue
Block a user