]> git.mxchange.org Git - simgear.git/commitdiff
canvas::Layout: support for hiding items.
authorThomas Geymayer <tomgey@gmail.com>
Sun, 20 Jul 2014 22:24:25 +0000 (00:24 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 20 Jul 2014 22:25:59 +0000 (00:25 +0200)
12 files changed:
simgear/canvas/CanvasWindow.cxx
simgear/canvas/CanvasWindow.hxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/layout/BoxLayout.cxx
simgear/canvas/layout/BoxLayout.hxx
simgear/canvas/layout/Layout.cxx
simgear/canvas/layout/Layout.hxx
simgear/canvas/layout/LayoutItem.cxx
simgear/canvas/layout/LayoutItem.hxx
simgear/canvas/layout/NasalWidget.cxx
simgear/canvas/layout/NasalWidget.hxx
simgear/canvas/layout/canvas_layout_test.cxx

index f4bf38dc06ea05448149e2a82b71046e86c11103..ac3e16a2bdfd975b5304cff8b8905f7cfec668ed 100644 (file)
@@ -172,6 +172,19 @@ namespace canvas
     return _capture_events;
   }
 
+  //----------------------------------------------------------------------------
+  void Window::setVisible(bool visible)
+  {
+    LayoutItem::setVisible(visible);
+    Element::setVisible(LayoutItem::isVisible());
+  }
+
+  //----------------------------------------------------------------------------
+  bool Window::isVisible() const
+  {
+    return Element::isVisible();
+  }
+
   //----------------------------------------------------------------------------
   void Window::raise()
   {
index 81917ed7c66828be45ff94634abc1627a7a893d5..330b6fb8ced6ef53d95fac6533ae9d1e1eb78f09 100644 (file)
@@ -84,6 +84,9 @@ namespace canvas
       bool isResizable() const;
       bool isCapturingEvents() const;
 
+      virtual void setVisible(bool visible);
+      virtual bool isVisible() const;
+
       /**
        * Moves window on top of all other windows with the same z-index.
        *
index 7ae7d22c436f52eef45f1c6fadc9ec8952fde01c..70f676f001d14fdbd915a6c221f0325d2633f244 100644 (file)
@@ -128,12 +128,12 @@ namespace canvas
       /**
        * Set visibility of the element.
        */
-      void setVisible(bool visible);
+      virtual void setVisible(bool visible);
 
       /**
        * Get whether the element is visible or hidden.
        */
-      bool isVisible() const;
+      virtual bool isVisible() const;
 
       osg::MatrixTransform* getMatrixTransform();
       osg::MatrixTransform const* getMatrixTransform() const;
index 263878f1b38b55de598d5408e51f3dd02f277609..c7a5f123b9249b97a22c99c52ab6c0e5ca1a481d 100644 (file)
@@ -278,11 +278,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)();
@@ -354,6 +356,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));
       }
@@ -363,6 +368,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;
       }
@@ -412,6 +420,9 @@ 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(),
@@ -451,6 +462,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(
@@ -476,6 +490,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)
index 59988a722a2b17813ee64ff7659027271a17bc8b..639871e9868e776333a05a3bea5d44a1ef910a83 100644 (file)
@@ -122,6 +122,8 @@ namespace canvas
       virtual SGVec2i maximumSizeImpl() const;
 
       virtual void doLayout(const SGRecti& geom);
+
+      virtual void visibilityChanged(bool visible);
   };
 
   /**
index ece4ddabe67ce35305a3ea51358f91ff3a5e26f7..8ae4e6e88b76987436a73d2e62bf55547f50cba7 100644 (file)
@@ -27,7 +27,7 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Layout::update()
   {
-    if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
+    if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) || !isVisible() )
       return;
 
     doLayout(_geometry);
@@ -85,6 +85,7 @@ namespace canvas
     padding     = 0;
     size        = 0;
     stretch     = 0;
+    visible     = false;
     has_hfw     = false;
     done        = false;
   }
@@ -120,7 +121,7 @@ namespace canvas
   void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
   {
     const int num_children = static_cast<int>(items.size());
-    _num_not_done = num_children;
+    _num_not_done = 0;
 
     SG_LOG( SG_GUI,
             SG_DEBUG,
@@ -148,6 +149,9 @@ namespace canvas
       for(int i = 0; i < num_children; ++i)
       {
         ItemData& d = items[i];
+        if( !d.visible )
+          continue;
+
         d.size = less_then_hint ? d.min_size : d.size_hint;
         d.padding = d.padding_orig;
         d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
@@ -162,10 +166,8 @@ namespace canvas
         );
 
         if( d.done )
-        {
-          _num_not_done -= 1;
           continue;
-        }
+        _num_not_done += 1;
 
         if( d.stretch > 0 )
         {
@@ -191,6 +193,8 @@ namespace canvas
         for(int i = 0; i < num_children; ++i)
         {
           ItemData& d = items[i];
+          if( !d.visible )
+            continue;
 
           SG_LOG(
             SG_GUI,
@@ -265,9 +269,18 @@ namespace canvas
     else
     {
       _space_left = space.size - space.max_size;
+      for(int i = 0; i < num_children; ++i)
+      {
+        if( items[i].visible )
+          _num_not_done += 1;
+      }
+
       for(int i = 0; i < num_children; ++i)
       {
         ItemData& d = items[i];
+        if( !d.visible )
+          continue;
+
         d.size = d.max_size;
 
         // Add superfluous space as padding
@@ -284,10 +297,11 @@ namespace canvas
     for(int i = 0; i < num_children; ++i)
     {
       ItemData const& d = items[i];
-      SG_LOG( SG_GUI,
-              SG_DEBUG,
-              i << ") pad=" << d.padding
-                << ", size = " << d.size );
+      if( d.visible )
+        SG_LOG(SG_GUI, SG_DEBUG, i << ") pad=" << d.padding
+                                   << ", size= " << d.size);
+      else
+        SG_LOG(SG_GUI, SG_DEBUG, i << ") [hidden]");
     }
   }
 
index 6a7fe3a1d87e4c483cefc32bef8bd69efaade946..b91767f46d5a2b156a50209079dd55566d42e25b 100644 (file)
@@ -88,7 +88,8 @@ namespace canvas
                 padding,      //<! padding before element (layouted)
                 size,         //<! layouted size
                 stretch;      //<! stretch factor
-        bool    has_hfw : 1,  //<! height for width
+        bool    visible : 1,
+                has_hfw : 1,  //<! height for width
                 done : 1;     //<! layouting done
 
         /** Clear values (reset to default/empty state) */
index 7c2e180b7856fd20c81790b62c8a78c63dc11dcb..3abb55a0b6d0bee5319d70809a6875245a986d61 100644 (file)
@@ -28,7 +28,7 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   LayoutItem::LayoutItem():
-    _flags(0),
+    _flags(VISIBLE),
     _size_hint(0, 0),
     _min_size(0, 0),
     _max_size(MAX_SIZE)
@@ -96,6 +96,29 @@ namespace canvas
     return heightForWidth(w);
   }
 
+  //----------------------------------------------------------------------------
+  void LayoutItem::setVisible(bool visible)
+  {
+    if( visible )
+      _flags &= ~EXPLICITLY_HIDDEN;
+    else
+      _flags |= EXPLICITLY_HIDDEN;
+
+    setVisibleInternal(visible);
+  }
+
+  //----------------------------------------------------------------------------
+  bool LayoutItem::isVisible() const
+  {
+    return _flags & VISIBLE;
+  }
+
+  //----------------------------------------------------------------------------
+  bool LayoutItem::isExplicitlyHidden() const
+  {
+    return _flags & EXPLICITLY_HIDDEN;
+  }
+
   //----------------------------------------------------------------------------
   void LayoutItem::invalidate()
   {
@@ -141,6 +164,8 @@ namespace canvas
     _parent = parent;
     LayoutItemRef parent_ref = parent.lock();
     setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
+
+    setVisibleInternal(!parent_ref || parent_ref->isVisible());
   }
 
   //----------------------------------------------------------------------------
@@ -167,5 +192,31 @@ namespace canvas
     return _max_size;
   }
 
+  //----------------------------------------------------------------------------
+  void LayoutItem::setVisibleInternal(bool visible)
+  {
+    LayoutItemRef parent = getParent();
+    if( isExplicitlyHidden() || (parent && !parent->isVisible()) )
+      visible = false;
+
+    if( isVisible() == visible )
+      return;
+
+    invalidateParent();
+
+    if( visible )
+      _flags |= VISIBLE;
+    else
+      _flags &= ~VISIBLE;
+
+    visibilityChanged(visible);
+  }
+
+  //----------------------------------------------------------------------------
+  void LayoutItem::callSetVisibleInternal(LayoutItem* item, bool visible)
+  {
+    item->setVisibleInternal(visible);
+  }
+
 } // namespace canvas
 } // namespace simgear
index bd3fb70c5f862d031cabbfc37fd9fd8ac315c471..e26e032fbcec80ace5046f5f93a15dcf9db8a60e 100644 (file)
@@ -68,6 +68,14 @@ namespace canvas
       virtual int heightForWidth(int w) const;
       virtual int minimumHeightForWidth(int w) const;
 
+      virtual void setVisible(bool visible);
+      virtual bool isVisible() const;
+
+      bool isExplicitlyHidden() const;
+
+      void show() { setVisible(true); }
+      void hide() { setVisible(false); }
+
       /**
        * Mark all cached data as invalid and require it to be recalculated.
        */
@@ -124,7 +132,9 @@ namespace canvas
         SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
                         | MINIMUM_SIZE_DIRTY
                         | MAXIMUM_SIZE_DIRTY,
-        LAST_FLAG = MAXIMUM_SIZE_DIRTY
+        EXPLICITLY_HIDDEN = MAXIMUM_SIZE_DIRTY << 1,
+        VISIBLE = EXPLICITLY_HIDDEN << 1,
+        LAST_FLAG = VISIBLE
       };
 
       CanvasWeakPtr     _canvas;
@@ -141,6 +151,18 @@ namespace canvas
       virtual SGVec2i minimumSizeImpl() const;
       virtual SGVec2i maximumSizeImpl() const;
 
+      /**
+       * @return whether the visibility has changed.
+       */
+      void setVisibleInternal(bool visible);
+
+      virtual void visibilityChanged(bool visible) {}
+
+      /**
+       * Allow calling the protected setVisibleImpl from derived classes
+       */
+      static void callSetVisibleInternal(LayoutItem* item, bool visible);
+
   };
 
 } // namespace canvas
index 01d3f55af2e30f179cbf2e8ebd242afdc42ffb10..0cf172e137846e4f8d9a398513da054d09970495 100644 (file)
@@ -285,5 +285,22 @@ namespace canvas
     );
   }
 
+  //----------------------------------------------------------------------------
+  void NasalWidget::visibilityChanged(bool visible)
+  {
+    try
+    {
+      callMethod<void>("visibilityChanged", visible);
+    }
+    catch( std::exception const& ex )
+    {
+      SG_LOG(
+        SG_GUI,
+        SG_WARN,
+        "NasalWidget::visibilityChanged: callback error: '" << ex.what() << "'"
+      );
+    }
+  }
+
 } // namespace canvas
 } // namespace simgear
index a55fa228723c29b3f00b0c10c5e09762a39b273d..34877e276e60251abafc9a30aecdc24f8e93f04b 100644 (file)
@@ -118,6 +118,8 @@ namespace canvas
       virtual SGVec2i minimumSizeImpl() const;
       virtual SGVec2i maximumSizeImpl() const;
 
+      virtual void visibilityChanged(bool visible);
+
   };
 
   typedef SGSharedPtr<NasalWidget> NasalWidgetRef;
index 5c81a1d89308855a64661d3d96ba3034fe6d3be1..ecab633397164be25d3fb957f52d2676877ae21e 100644 (file)
@@ -23,6 +23,8 @@
 #include "NasalWidget.hxx"
 
 #include <simgear/debug/logstream.hxx>
+#include <simgear/nasal/cppbind/NasalContext.hxx>
+
 #include <cstdlib>
 
 //------------------------------------------------------------------------------
@@ -72,6 +74,12 @@ class TestWidget:
     virtual SGVec2i sizeHintImpl() const { return _size_hint; }
     virtual SGVec2i minimumSizeImpl() const { return _min_size; }
     virtual SGVec2i maximumSizeImpl() const { return _max_size; }
+
+    virtual void visibilityChanged(bool visible)
+    {
+      if( !visible )
+        _geom.set(0, 0, 0, 0);
+    }
 };
 
 class TestWidgetHFW:
@@ -332,6 +340,77 @@ BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
   BOOST_CHECK( !w2->getParent() );
 }
 
+//------------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE( boxlayout_visibility )
+{
+  sc::BoxLayoutRef hbox( new sc::HBoxLayout );
+  TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
+                                    SGVec2i(32, 32) ) ),
+                w2( new TestWidget(*w1) ),
+                w3( new TestWidget(*w1) );
+
+  hbox->addItem(w1);
+  hbox->addItem(w2);
+  hbox->addItem(w3);
+
+  BOOST_REQUIRE_EQUAL(hbox->sizeHint().x(), 3 * 32 + 2 * hbox->spacing());
+
+  hbox->setGeometry(SGRecti(0, 0, 69, 32));
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0,  0, 20, 32));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
+  BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
+
+  w2->setVisible(false);
+
+  BOOST_REQUIRE(hbox->isVisible());
+  BOOST_REQUIRE(w1->isVisible());
+  BOOST_REQUIRE(!w2->isVisible());
+  BOOST_REQUIRE(w2->isExplicitlyHidden());
+  BOOST_REQUIRE(w3->isVisible());
+
+  BOOST_CHECK_EQUAL(hbox->sizeHint().x(), 2 * 32 + 1 * hbox->spacing());
+
+  hbox->update();
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0,  0, 32, 32));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0,  0,  0,  0));
+  BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(37, 0, 32, 32));
+
+  hbox->setVisible(false);
+
+  BOOST_REQUIRE(!hbox->isVisible());
+  BOOST_REQUIRE(hbox->isExplicitlyHidden());
+  BOOST_REQUIRE(!w1->isVisible());
+  BOOST_REQUIRE(!w1->isExplicitlyHidden());
+  BOOST_REQUIRE(!w2->isVisible());
+  BOOST_REQUIRE(w2->isExplicitlyHidden());
+  BOOST_REQUIRE(!w3->isVisible());
+  BOOST_REQUIRE(!w3->isExplicitlyHidden());
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 0, 0));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
+  BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(0, 0, 0, 0));
+
+  w2->setVisible(true);
+
+  BOOST_REQUIRE(!w2->isVisible());
+  BOOST_REQUIRE(!w2->isExplicitlyHidden());
+
+  hbox->setVisible(true);
+
+  BOOST_REQUIRE(hbox->isVisible());
+  BOOST_REQUIRE(w1->isVisible());
+  BOOST_REQUIRE(w2->isVisible());
+  BOOST_REQUIRE(w3->isVisible());
+
+  hbox->update();
+
+  BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0,  0, 20, 32));
+  BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
+  BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
+}
+
 //------------------------------------------------------------------------------
 BOOST_AUTO_TEST_CASE( boxlayout_hfw )
 {
@@ -423,13 +502,30 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
   BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
 }
 
+// TODO extend to_nasal_helper for automatic argument conversion
+static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
+{
+  sc::NasalWidget* w = ctx.from_nasal<sc::NasalWidget*>(ctx.me);
+
+  if( !ctx.requireArg<bool>(0) )
+    w->setGeometry(SGRecti(0, 0, -1, -1));
+
+  return naNil();
+}
+
 //------------------------------------------------------------------------------
 BOOST_AUTO_TEST_CASE( nasal_widget )
 {
-  naContext c = naNewContext();
-  naRef me = naNewHash(c);
+  nasal::Context c;
+  nasal::Hash globals = c.newHash();
+
+  nasal::Object::setupGhost();
+  nasal::Ghost<sc::LayoutItemRef>::init("LayoutItem");
+  sc::NasalWidget::setupGhost(globals);
 
-  sc::NasalWidgetRef w( new sc::NasalWidget(me) );
+  nasal::Hash me = c.newHash();
+  me.set("visibilityChanged", &f_Widget_visibilityChanged);
+  sc::NasalWidgetRef w( new sc::NasalWidget(me.get_naRef()) );
 
   // Default layout sizes (no user set values)
   BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(16, 16));
@@ -463,5 +559,6 @@ BOOST_AUTO_TEST_CASE( nasal_widget )
   BOOST_CHECK_EQUAL(w->sizeHint(),    SGVec2i(3, 22));
   BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
 
-  naFreeContext(c);
+  w->setVisible(false);
+  BOOST_CHECK_EQUAL(w->geometry(), SGRecti(0, 0, -1, -1));
 }