]> git.mxchange.org Git - simgear.git/commitdiff
canvas::BoxLayout: add custom additional whitespace (spacer/stretch)
authorThomas Geymayer <tomgey@gmail.com>
Sun, 8 Jun 2014 21:30:11 +0000 (23:30 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 8 Jun 2014 21:30:11 +0000 (23:30 +0200)
simgear/canvas/layout/BoxLayout.cxx
simgear/canvas/layout/BoxLayout.hxx
simgear/canvas/layout/CMakeLists.txt
simgear/canvas/layout/LayoutItem.cxx
simgear/canvas/layout/LayoutItem.hxx
simgear/canvas/layout/SpacerItem.cxx [new file with mode: 0644]
simgear/canvas/layout/SpacerItem.hxx [new file with mode: 0644]
simgear/canvas/layout/canvas_layout_test.cxx

index cabe0ba90463032cfa7e88642a5d2643454a1775..5ba2ad3640f3f1b6440aa1580aae3b6906a24c21 100644 (file)
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "BoxLayout.hxx"
+#include "SpacerItem.hxx"
 #include <simgear/canvas/Canvas.hxx>
 
 namespace simgear
@@ -39,6 +40,24 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
+  {
+    insertItem(-1, item, stretch);
+  }
+
+  //----------------------------------------------------------------------------
+  void BoxLayout::addStretch(int stretch)
+  {
+    insertStretch(-1, stretch);
+  }
+
+  //----------------------------------------------------------------------------
+  void BoxLayout::addSpacing(int size)
+  {
+    insertSpacing(-1, size);
+  }
+
+  //----------------------------------------------------------------------------
+  void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
   {
     ItemData item_data = {0};
     item_data.layout_item = item;
@@ -47,11 +66,31 @@ namespace canvas
     item->setCanvas(_canvas);
     item->setParent(this);
 
-    _layout_items.push_back(item_data);
+    if( index < 0 )
+      _layout_items.push_back(item_data);
+    else
+      _layout_items.insert(_layout_items.begin() + index, item_data);
 
     invalidate();
   }
 
+  //----------------------------------------------------------------------------
+  void BoxLayout::insertStretch(int index, int stretch)
+  {
+    insertItem(index, LayoutItemRef(new SpacerItem()), stretch);
+  }
+
+  //----------------------------------------------------------------------------
+  void BoxLayout::insertSpacing(int index, int size)
+  {
+    SGVec2i size_hint = horiz()
+                          ? SGVec2i(size, 0)
+                          : SGVec2i(0, size),
+                max_size  = size_hint;
+
+    insertItem(index, LayoutItemRef(new SpacerItem(size_hint, max_size)));
+  }
+
   //----------------------------------------------------------------------------
   void BoxLayout::setStretch(size_t index, int stretch)
   {
@@ -90,24 +129,20 @@ namespace canvas
   //----------------------------------------------------------------------------
   void BoxLayout::setDirection(Direction dir)
   {
+    _direction = dir;
     _get_layout_coord = &SGVec2i::x;
     _get_fixed_coord = &SGVec2i::y;
 
-    if( dir == TopToBottom || dir == BottomToTop )
+    if( !horiz() )
       std::swap(_get_layout_coord, _get_fixed_coord);
 
-    _reverse = (dir == RightToLeft || dir == BottomToTop );
-
     invalidate();
   }
 
   //----------------------------------------------------------------------------
   BoxLayout::Direction BoxLayout::direction() const
   {
-    if( _get_layout_coord == static_cast<CoordGetter>(&SGVec2i::x) )
-      return _reverse ? RightToLeft : LeftToRight;
-    else
-      return _reverse ? BottomToTop : TopToBottom;
+    return _direction;
   }
 
   //----------------------------------------------------------------------------
@@ -119,6 +154,12 @@ namespace canvas
       _layout_items[i].layout_item->setCanvas(canvas);
   }
 
+  //----------------------------------------------------------------------------
+  bool BoxLayout::horiz() const
+  {
+    return (_direction == LeftToRight) || (_direction == RightToLeft);
+  }
+
   //----------------------------------------------------------------------------
   void BoxLayout::updateSizeHints() const
   {
@@ -140,15 +181,19 @@ namespace canvas
       item_data.max_size  = (item.maximumSize().*_get_layout_coord)();
       item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
 
-      if( is_first )
+      if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
       {
-        item_data.padding_orig = 0;
-        is_first = false;
+        if( is_first )
+        {
+          item_data.padding_orig = 0;
+          is_first = false;
+        }
+        else
+        {
+          item_data.padding_orig = _padding;
+          _layout_data.padding += item_data.padding_orig;
+        }
       }
-      else
-        item_data.padding_orig = _padding;
-
-     _layout_data.padding += item_data.padding_orig;
 
       // Add sizes of all children in layout direction
       safeAdd(min_size.x(),  item_data.min_size);
@@ -160,7 +205,7 @@ namespace canvas
                                 (item.minimumSize().*_get_fixed_coord)() );
       max_size.y()  = std::max( max_size.y(),
                                 (item.maximumSize().*_get_fixed_coord)() );
-      size_hint.y() = std::max( min_size.y(),
+      size_hint.y() = std::max( size_hint.y(),
                                 (item.sizeHint().*_get_fixed_coord)() );
     }
 
@@ -216,14 +261,16 @@ namespace canvas
     int fixed_size = (geom.size().*_get_fixed_coord)();
     SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
                      (geom.pos().*_get_fixed_coord)() );
-    if( _reverse )
+
+    bool reverse = (_direction == RightToLeft) || (_direction == BottomToTop);
+    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];
-      cur_pos.x() += _reverse ? -data.padding - data.size : data.padding;
+      cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
 
       SGVec2i size(
         data.size,
@@ -242,7 +289,7 @@ namespace canvas
         (size.*_get_fixed_coord)()
       ));
 
-      if( !_reverse )
+      if( !reverse )
         cur_pos.x() += data.size;
       cur_pos.y() -= offset_fixed;
     }
index 01c3077c5219f0d78eb1ed3ac83f476363d3cfd4..105372743be02668b17778c61270574f53edadf8 100644 (file)
@@ -45,6 +45,16 @@ namespace canvas
 
       void addItem(const LayoutItemRef& item, int stretch);
 
+      void addStretch(int stretch = 0);
+
+      void addSpacing(int size);
+
+      void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
+
+      void insertStretch(int index, int stretch = 0);
+
+      void insertSpacing(int index, int size);
+
       /**
        * Set the stretch factor of the item at position @a index to @a stretch.
        */
@@ -63,6 +73,8 @@ namespace canvas
 
       virtual void setCanvas(const CanvasWeakPtr& canvas);
 
+      bool horiz() const;
+
     protected:
 
       typedef const int& (SGVec2i::*CoordGetter)() const;
@@ -72,7 +84,7 @@ namespace canvas
                                         //   (fixed) direction
 
       int _padding;
-      bool _reverse; //<! if true, right-to-left/bottom-to-top layouting
+      Direction _direction;
 
       mutable std::vector<ItemData> _layout_items;
       mutable ItemData _layout_data;
index f02c30fb94d4e7d910d57cdc12fbc4f4ed5759e5..f15cc4a8ed39549edf7c26d12a9be3cbb18a09c8 100644 (file)
@@ -5,6 +5,7 @@ set(HEADERS
   Layout.hxx
   LayoutItem.hxx
   NasalWidget.hxx
+  SpacerItem.hxx
 )
 
 set(SOURCES
@@ -12,6 +13,7 @@ set(SOURCES
   Layout.cxx
   LayoutItem.cxx
   NasalWidget.cxx
+  SpacerItem.cxx
 )
 
 simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
index 31be629ea309116211ffb5238d13215277094fad..3ebeeddc6109f1d8a9677cc7e62ba9bdfa042cff 100644 (file)
@@ -23,10 +23,15 @@ namespace simgear
 {
 namespace canvas
 {
+  const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
+                                      SGLimits<int>::max() );
 
   //----------------------------------------------------------------------------
   LayoutItem::LayoutItem():
-    _flags(0)
+    _flags(0),
+    _size_hint(16, 16),
+    _min_size(0, 0),
+    _max_size(MAX_SIZE)
   {
     invalidate();
   }
@@ -132,19 +137,19 @@ namespace canvas
   //----------------------------------------------------------------------------
   SGVec2i LayoutItem::sizeHintImpl() const
   {
-    return SGVec2i(16, 16);
+    return _size_hint;
   }
 
   //----------------------------------------------------------------------------
   SGVec2i LayoutItem::minimumSizeImpl() const
   {
-    return SGVec2i(0, 0);
+    return _min_size;
   }
 
   //----------------------------------------------------------------------------
   SGVec2i LayoutItem::maximumSizeImpl() const
   {
-    return SGVec2i(SGLimits<int>::max(), SGLimits<int>::max());
+    return _max_size;
   }
 
 } // namespace canvas
index 740ccd1a97034d29bf9661ccfbf87353698a4255..6654349a7a4a7218726bcfbc177025de794d589b 100644 (file)
@@ -43,6 +43,8 @@ namespace canvas
   {
     public:
 
+      static const SGVec2i MAX_SIZE;
+
       LayoutItem();
       virtual ~LayoutItem();
 
diff --git a/simgear/canvas/layout/SpacerItem.cxx b/simgear/canvas/layout/SpacerItem.cxx
new file mode 100644 (file)
index 0000000..9482f43
--- /dev/null
@@ -0,0 +1,36 @@
+// Element providing blank space in a layout.
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#include "SpacerItem.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+  //----------------------------------------------------------------------------
+  SpacerItem::SpacerItem( const SGVec2i& size,
+                          const SGVec2i& max_size )
+  {
+    _size_hint = size;
+    _min_size  = size;
+    _max_size  = max_size;
+  }
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/layout/SpacerItem.hxx b/simgear/canvas/layout/SpacerItem.hxx
new file mode 100644 (file)
index 0000000..b3b4f4e
--- /dev/null
@@ -0,0 +1,43 @@
+///@file Element providing blank space in a layout.
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef SG_CANVAS_SPACER_ITEM_HXX_
+#define SG_CANVAS_SPACER_ITEM_HXX_
+
+#include "LayoutItem.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+  /**
+   * Element for providing blank space in a layout.
+   */
+  class SpacerItem:
+    public LayoutItem
+  {
+    public:
+      SpacerItem( const SGVec2i& size = SGVec2i(0, 0),
+                  const SGVec2i& max_size = MAX_SIZE );
+
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* SG_CANVAS_SPACER_ITEM_HXX_ */
index ffbc1c90208bb79f2e98bda7cc1a76383b27756f..b05afd48b68a330d58f2f19c1811e0858ff30acf 100644 (file)
@@ -191,6 +191,42 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
   }
 }
 
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( spacer_layouting )
+{
+  sc::HBoxLayout hbox;
+  TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
+                                    SGVec2i(32, 32),
+                                    SGVec2i(9999, 9999) ) ),
+                w2( new TestWidget(*w1) );
+
+  hbox.addItem(w1);
+  hbox.addItem(w2);
+  hbox.addStretch(1);
+
+  BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(37, 16));
+  BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(69, 32));
+  BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+
+  hbox.setGeometry(SGRecti(0, 0, 256, 40));
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0,  0, 32, 40));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(37, 0, 32, 40));
+
+  // now center with increased spacing between both widgets
+  hbox.insertStretch(0, 1);
+  hbox.insertSpacing(2, 10);
+
+  BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(47, 16));
+  BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(79, 32));
+  BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+
+  hbox.update();
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(88,  0, 32, 40));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(135, 0, 32, 40));
+}
+
 //------------------------------------------------------------------------------
 BOOST_AUTO_TEST_CASE( vertical_layout)
 {