diff --git a/simgear/canvas/layout/BoxLayout.cxx b/simgear/canvas/layout/BoxLayout.cxx index 3e1d37ff..1c470f4f 100644 --- a/simgear/canvas/layout/BoxLayout.cxx +++ b/simgear/canvas/layout/BoxLayout.cxx @@ -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(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; } } diff --git a/simgear/canvas/layout/BoxLayout.hxx b/simgear/canvas/layout/BoxLayout.hxx index 2d33c016..c5fe6d28 100644 --- a/simgear/canvas/layout/BoxLayout.hxx +++ b/simgear/canvas/layout/BoxLayout.hxx @@ -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); diff --git a/simgear/canvas/layout/Layout.cxx b/simgear/canvas/layout/Layout.cxx index ee24be6e..b7e5b76b 100644 --- a/simgear/canvas/layout/Layout.cxx +++ b/simgear/canvas/layout/Layout.cxx @@ -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 ) - _num_not_done += 1; + 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; - // Add superfluous space as padding - d.padding = d.padding_orig + _space_left - // Padding after last child... - / (_num_not_done + 1); + int space_add = 0; - _space_left -= d.padding - d.padding_orig; - _num_not_done -= 1; + 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 + space_add = _space_left + // Padding after last child... + / (_num_not_done + 1); + _num_not_done -= 1; + + d.padding += space_add; + } + + _space_left -= space_add; } } diff --git a/simgear/canvas/layout/Layout.hxx b/simgear/canvas/layout/Layout.hxx index 0fee1471..5abbf07d 100644 --- a/simgear/canvas/layout/Layout.hxx +++ b/simgear/canvas/layout/Layout.hxx @@ -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); /** diff --git a/simgear/canvas/layout/LayoutItem.cxx b/simgear/canvas/layout/LayoutItem.cxx index f585b257..8db90285 100644 --- a/simgear/canvas/layout/LayoutItem.cxx +++ b/simgear/canvas/layout/LayoutItem.cxx @@ -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::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) { diff --git a/simgear/canvas/layout/LayoutItem.hxx b/simgear/canvas/layout/LayoutItem.hxx index 79347cce..2807daa6 100644 --- a/simgear/canvas/layout/LayoutItem.hxx +++ b/simgear/canvas/layout/LayoutItem.hxx @@ -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, diff --git a/simgear/canvas/layout/canvas_layout_test.cxx b/simgear/canvas/layout/canvas_layout_test.cxx index a95aa760..d695f2aa 100644 --- a/simgear/canvas/layout/canvas_layout_test.cxx +++ b/simgear/canvas/layout/canvas_layout_test.cxx @@ -110,45 +110,45 @@ typedef SGSharedPtr 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)); - // Test more space then preferred, but less than maximum - { - sc::HBoxLayout hbox; - TestWidgetRef w1( new TestWidget( SGVec2i(16, 16), - SGVec2i(32, 32), - SGVec2i(9999, 32) ) ), - w2( new TestWidget(*w1) ); + // ...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. - hbox.addItem(w1); - hbox.addItem(w2); + // 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)); - hbox.setGeometry( SGRecti(0, 0, 256, 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)); - BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32)); - BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 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)); - hbox.setStretch(0, 1); - hbox.setStretch(1, 1); + // 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)); +} - BOOST_CHECK_EQUAL(hbox.stretch(0), 1); - BOOST_CHECK_EQUAL(hbox.stretch(1), 1); +//------------------------------------------------------------------------------ +// Test more space then preferred, but less than maximum +BOOST_AUTO_TEST_CASE( hbox_pref_to_max ) +{ + sc::BoxLayoutRef hbox(new sc::HBoxLayout()); + TestWidgetRef w1( new TestWidget( SGVec2i(16, 16), + SGVec2i(32, 32), + SGVec2i(9999, 32) ) ), + w2( new TestWidget(*w1) ); - hbox.update(); + hbox->addItem(w1); + hbox->addItem(w2); - BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32)); - BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32)); + hbox->setGeometry( SGRecti(0, 0, 256, 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_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32)); + BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32)); - hbox.removeItem(w1); + hbox->setStretch(0, 1); + hbox->setStretch(1, 1); - BOOST_CHECK( !hbox.setStretchFactor(w1, 0) ); - } + BOOST_CHECK_EQUAL(hbox->stretch(0), 1); + BOOST_CHECK_EQUAL(hbox->stretch(1), 1); + + 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); + + hbox->removeItem(w1); + + 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)