]> git.mxchange.org Git - simgear.git/blobdiff - simgear/canvas/layout/BoxLayout.cxx
canvas::Layout: support for contents margins.
[simgear.git] / simgear / canvas / layout / BoxLayout.cxx
index a981db99c726020325b9add8a3e0837eca1aa06b..3e1d37ffde09a9336e6019e8de3f9fbd6481454e 100644 (file)
@@ -32,6 +32,13 @@ namespace canvas
     setDirection(dir);
   }
 
+  //----------------------------------------------------------------------------
+  BoxLayout::~BoxLayout()
+  {
+    _parent.reset(); // No need to invalidate parent again...
+    clear();
+  }
+
   //----------------------------------------------------------------------------
   void BoxLayout::addItem(const LayoutItemRef& item)
   {
@@ -63,8 +70,12 @@ namespace canvas
     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);
@@ -114,6 +125,8 @@ namespace canvas
 
     LayoutItems::iterator it = _layout_items.begin() + index;
     LayoutItemRef item = it->layout_item;
+    item->onRemove();
+    item->setParent(LayoutItemWeakRef());
     _layout_items.erase(it);
 
     invalidate();
@@ -121,6 +134,20 @@ namespace canvas
     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)
   {
@@ -131,6 +158,24 @@ namespace canvas
     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
   {
@@ -184,26 +229,6 @@ namespace canvas
     return _layout_data.has_hfw;
   }
 
-  //----------------------------------------------------------------------------
-  int BoxLayout::heightForWidth(int w) const
-  {
-    if( !hasHeightForWidth() )
-      return -1;
-
-    updateWFHCache(w);
-    return _hfw_height;
-  }
-
-  //----------------------------------------------------------------------------
-  int BoxLayout::minimumHeightForWidth(int w) const
-  {
-    if( !hasHeightForWidth() )
-      return -1;
-
-    updateWFHCache(w);
-    return _hfw_min_height;
-  }
-
   //----------------------------------------------------------------------------
   void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
   {
@@ -233,11 +258,13 @@ namespace canvas
 
     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)();
@@ -258,9 +285,9 @@ namespace canvas
       }
 
       // 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(),
@@ -273,9 +300,9 @@ namespace canvas
       _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();
@@ -309,6 +336,9 @@ namespace canvas
       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));
       }
@@ -318,6 +348,9 @@ namespace canvas
       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;
       }
@@ -347,6 +380,27 @@ namespace canvas
     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)
   {
@@ -367,19 +421,25 @@ namespace canvas
       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() );
 
-          int d = data.layout_item->minimumHeightForWidth(w) - data.min_size;
-          data.min_size += d;
-          _layout_data.min_size += d;
+          data.min_size = data.mhfw(w);
+          data.size_hint = data.hfw(w);
 
-          d = data.layout_item->heightForWidth(w) - data.size_hint;
-          data.size_hint += d;
-          _layout_data.size_hint += d;
+          // 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();
         }
       }
     }
@@ -403,6 +463,9 @@ namespace canvas
     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(
@@ -428,6 +491,13 @@ namespace canvas
     }
   }
 
+  //----------------------------------------------------------------------------
+  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)