From: Thomas Geymayer Date: Sun, 20 Jul 2014 22:24:25 +0000 (+0200) Subject: canvas::Layout: support for hiding items. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=557e4f75b5012b67199ba20249ee03b429a65406;p=simgear.git canvas::Layout: support for hiding items. --- diff --git a/simgear/canvas/CanvasWindow.cxx b/simgear/canvas/CanvasWindow.cxx index f4bf38dc..ac3e16a2 100644 --- a/simgear/canvas/CanvasWindow.cxx +++ b/simgear/canvas/CanvasWindow.cxx @@ -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() { diff --git a/simgear/canvas/CanvasWindow.hxx b/simgear/canvas/CanvasWindow.hxx index 81917ed7..330b6fb8 100644 --- a/simgear/canvas/CanvasWindow.hxx +++ b/simgear/canvas/CanvasWindow.hxx @@ -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. * diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index 7ae7d22c..70f676f0 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -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; diff --git a/simgear/canvas/layout/BoxLayout.cxx b/simgear/canvas/layout/BoxLayout.cxx index 263878f1..c7a5f123 100644 --- a/simgear/canvas/layout/BoxLayout.cxx +++ b/simgear/canvas/layout/BoxLayout.cxx @@ -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::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) diff --git a/simgear/canvas/layout/BoxLayout.hxx b/simgear/canvas/layout/BoxLayout.hxx index 59988a72..639871e9 100644 --- a/simgear/canvas/layout/BoxLayout.hxx +++ b/simgear/canvas/layout/BoxLayout.hxx @@ -122,6 +122,8 @@ namespace canvas virtual SGVec2i maximumSizeImpl() const; virtual void doLayout(const SGRecti& geom); + + virtual void visibilityChanged(bool visible); }; /** diff --git a/simgear/canvas/layout/Layout.cxx b/simgear/canvas/layout/Layout.cxx index ece4ddab..8ae4e6e8 100644 --- a/simgear/canvas/layout/Layout.cxx +++ b/simgear/canvas/layout/Layout.cxx @@ -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& items, const ItemData& space) { const int num_children = static_cast(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]"); } } diff --git a/simgear/canvas/layout/Layout.hxx b/simgear/canvas/layout/Layout.hxx index 6a7fe3a1..b91767f4 100644 --- a/simgear/canvas/layout/Layout.hxx +++ b/simgear/canvas/layout/Layout.hxx @@ -88,7 +88,8 @@ namespace canvas padding, //_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 diff --git a/simgear/canvas/layout/LayoutItem.hxx b/simgear/canvas/layout/LayoutItem.hxx index bd3fb70c..e26e032f 100644 --- a/simgear/canvas/layout/LayoutItem.hxx +++ b/simgear/canvas/layout/LayoutItem.hxx @@ -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 diff --git a/simgear/canvas/layout/NasalWidget.cxx b/simgear/canvas/layout/NasalWidget.cxx index 01d3f55a..0cf172e1 100644 --- a/simgear/canvas/layout/NasalWidget.cxx +++ b/simgear/canvas/layout/NasalWidget.cxx @@ -285,5 +285,22 @@ namespace canvas ); } + //---------------------------------------------------------------------------- + void NasalWidget::visibilityChanged(bool visible) + { + try + { + callMethod("visibilityChanged", visible); + } + catch( std::exception const& ex ) + { + SG_LOG( + SG_GUI, + SG_WARN, + "NasalWidget::visibilityChanged: callback error: '" << ex.what() << "'" + ); + } + } + } // namespace canvas } // namespace simgear diff --git a/simgear/canvas/layout/NasalWidget.hxx b/simgear/canvas/layout/NasalWidget.hxx index a55fa228..34877e27 100644 --- a/simgear/canvas/layout/NasalWidget.hxx +++ b/simgear/canvas/layout/NasalWidget.hxx @@ -118,6 +118,8 @@ namespace canvas virtual SGVec2i minimumSizeImpl() const; virtual SGVec2i maximumSizeImpl() const; + virtual void visibilityChanged(bool visible); + }; typedef SGSharedPtr NasalWidgetRef; diff --git a/simgear/canvas/layout/canvas_layout_test.cxx b/simgear/canvas/layout/canvas_layout_test.cxx index 5c81a1d8..ecab6333 100644 --- a/simgear/canvas/layout/canvas_layout_test.cxx +++ b/simgear/canvas/layout/canvas_layout_test.cxx @@ -23,6 +23,8 @@ #include "NasalWidget.hxx" #include +#include + #include //------------------------------------------------------------------------------ @@ -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(ctx.me); + + if( !ctx.requireArg(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::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)); }