setDirection(dir);
}
+ //----------------------------------------------------------------------------
+ BoxLayout::~BoxLayout()
+ {
+ _parent.reset(); // No need to invalidate parent again...
+ clear();
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::addItem(const LayoutItemRef& item)
{
item_data.layout_item = item;
item_data.stretch = std::max(0, stretch);
- item->setCanvas(_canvas);
- item->setParent(this);
+ if( SGWeakReferenced::count(this) )
+ item->setParent(this);
+ else
+ SG_LOG( SG_GUI,
+ SG_WARN,
+ "Adding item to expired or non-refcounted layout" );
if( index < 0 )
_layout_items.push_back(item_data);
LayoutItems::iterator it = _layout_items.begin() + index;
LayoutItemRef item = it->layout_item;
+ item->onRemove();
+ item->setParent(LayoutItemWeakRef());
_layout_items.erase(it);
invalidate();
return item;
}
+ //----------------------------------------------------------------------------
+ void BoxLayout::clear()
+ {
+ for( LayoutItems::iterator it = _layout_items.begin();
+ it != _layout_items.end();
+ ++it )
+ {
+ it->layout_item->onRemove();
+ it->layout_item->setParent(LayoutItemWeakRef());
+ }
+ _layout_items.clear();
+ invalidate();
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::setStretch(size_t index, int stretch)
{
invalidate();
}
+ //----------------------------------------------------------------------------
+ bool BoxLayout::setStretchFactor(const LayoutItemRef& item, int stretch)
+ {
+ for( LayoutItems::iterator it = _layout_items.begin();
+ it != _layout_items.end();
+ ++it )
+ {
+ if( item == it->layout_item )
+ {
+ it->stretch = std::max(0, stretch);
+ invalidate();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
//----------------------------------------------------------------------------
int BoxLayout::stretch(size_t index) const
{
return _direction;
}
+ //----------------------------------------------------------------------------
+ bool BoxLayout::hasHeightForWidth() const
+ {
+ if( _flags & SIZE_INFO_DIRTY )
+ updateSizeHints();
+
+ return _layout_data.has_hfw;
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
{
size_hint(0, 0);
_layout_data.reset();
+ _hfw_width = _hfw_height = _hfw_min_height = -1;
+
bool is_first = true;
for(size_t i = 0; i < _layout_items.size(); ++i)
{
- // TODO check visible
-
ItemData& item_data = _layout_items[i];
LayoutItem const& item = *item_data.layout_item;
+ item_data.visible = item.isVisible();
+ if( !item_data.visible )
+ continue;
+
item_data.min_size = (item.minimumSize().*_get_layout_coord)();
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
+ item_data.has_hfw = item.hasHeightForWidth();
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
{
}
// Add sizes of all children in layout direction
- safeAdd(min_size.x(), item_data.min_size);
- safeAdd(max_size.x(), item_data.max_size);
- safeAdd(size_hint.x(), item_data.size_hint);
+ SGMisc<int>::addClipOverflowInplace(min_size.x(), item_data.min_size);
+ SGMisc<int>::addClipOverflowInplace(max_size.x(), item_data.max_size);
+ SGMisc<int>::addClipOverflowInplace(size_hint.x(), item_data.size_hint);
// Take maximum in fixed (non-layouted) direction
min_size.y() = std::max( min_size.y(),
(item.maximumSize().*_get_fixed_coord)() );
size_hint.y() = std::max( size_hint.y(),
(item.sizeHint().*_get_fixed_coord)() );
+
+ _layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
}
- safeAdd(min_size.x(), _layout_data.padding);
- safeAdd(max_size.x(), _layout_data.padding);
- safeAdd(size_hint.x(), _layout_data.padding);
+ SGMisc<int>::addClipOverflowInplace(min_size.x(), _layout_data.padding);
+ SGMisc<int>::addClipOverflowInplace(max_size.x(), _layout_data.padding);
+ SGMisc<int>::addClipOverflowInplace(size_hint.x(), _layout_data.padding);
_layout_data.min_size = min_size.x();
_layout_data.max_size = max_size.x();
_flags &= ~SIZE_INFO_DIRTY;
}
+ //----------------------------------------------------------------------------
+ void BoxLayout::updateWFHCache(int w) const
+ {
+ if( w == _hfw_width )
+ return;
+
+ _hfw_height = 0;
+ _hfw_min_height = 0;
+
+ if( horiz() )
+ {
+ _layout_data.size = w;
+ const_cast<BoxLayout*>(this)->distribute(_layout_items, _layout_data);
+
+ for(size_t i = 0; i < _layout_items.size(); ++i)
+ {
+ ItemData const& data = _layout_items[i];
+ if( !data.visible )
+ continue;
+
+ _hfw_height = std::max(_hfw_height, data.hfw(data.size));
+ _hfw_min_height = std::max(_hfw_min_height, data.mhfw(data.size));
+ }
+ }
+ else
+ {
+ for(size_t i = 0; i < _layout_items.size(); ++i)
+ {
+ ItemData const& data = _layout_items[i];
+ if( !data.visible )
+ continue;
+
+ _hfw_height += data.hfw(w) + data.padding_orig;
+ _hfw_min_height += data.mhfw(w) + data.padding_orig;
+ }
+ }
+
+ _hfw_width = w;
+ }
+
//----------------------------------------------------------------------------
SGVec2i BoxLayout::sizeHintImpl() const
{
return _max_size;
}
+
+ //----------------------------------------------------------------------------
+ int BoxLayout::heightForWidthImpl(int w) const
+ {
+ if( !hasHeightForWidth() )
+ return -1;
+
+ updateWFHCache(w);
+ return _hfw_height;
+ }
+
+ //----------------------------------------------------------------------------
+ int BoxLayout::minimumHeightForWidthImpl(int w) const
+ {
+ if( !hasHeightForWidth() )
+ return -1;
+
+ updateWFHCache(w);
+ return _hfw_min_height;
+ }
+
//----------------------------------------------------------------------------
void BoxLayout::doLayout(const SGRecti& geom)
{
if( _flags & SIZE_INFO_DIRTY )
updateSizeHints();
+ // Store current size hints because vertical layouts containing
+ // height-for-width items the size hints are update for the actual width of
+ // the layout
+ int min_size_save = _layout_data.min_size,
+ size_hint_save = _layout_data.size_hint;
+
_layout_data.size = (geom.size().*_get_layout_coord)();
+
+ // update width dependent data for layouting of vertical layouts
+ if( _layout_data.has_hfw && !horiz() )
+ {
+ for(size_t i = 0; i < _layout_items.size(); ++i)
+ {
+ ItemData& data = _layout_items[i];
+ if( !data.visible )
+ continue;
+
+ if( data.has_hfw )
+ {
+ int w = SGMisc<int>::clip( geom.width(),
+ data.layout_item->minimumSize().x(),
+ data.layout_item->maximumSize().x() );
+
+ data.min_size = data.mhfw(w);
+ data.size_hint = data.hfw(w);
+
+ // Update size hints for layouting with difference to size hints
+ // calculated by using the size hints provided (without trading
+ // height for width)
+ _layout_data.min_size += data.min_size
+ - data.layout_item->minimumSize().y();
+ _layout_data.size_hint += data.size_hint
+ - data.layout_item->sizeHint().y();
+ }
+ }
+ }
+
+ // now do the actual layouting
distribute(_layout_items, _layout_data);
+ // Restore size hints possibly changed by vertical layouting
+ _layout_data.min_size = min_size_save;
+ _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 cur_pos( (geom.pos().*_get_layout_coord)(),
(geom.pos().*_get_fixed_coord)() );
if( reverse )
cur_pos.x() += (geom.size().*_get_layout_coord)();
- // TODO handle reverse layouting (rtl/btt)
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData const& data = _layout_items[i];
+ if( !data.visible )
+ continue;
+
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
SGVec2i size(
}
}
+ //----------------------------------------------------------------------------
+ void BoxLayout::visibilityChanged(bool visible)
+ {
+ for(size_t i = 0; i < _layout_items.size(); ++i)
+ callSetVisibleInternal(_layout_items[i].layout_item.get(), visible);
+ }
+
//----------------------------------------------------------------------------
HBoxLayout::HBoxLayout():
BoxLayout(LeftToRight)