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()
{
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.
*
/**
* 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;
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)();
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));
}
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;
}
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(),
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)
virtual SGVec2i maximumSizeImpl() const;
virtual void doLayout(const SGRecti& geom);
+
+ virtual void visibilityChanged(bool visible);
};
/**
//----------------------------------------------------------------------------
void Layout::update()
{
- if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
+ if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) || !isVisible() )
return;
doLayout(_geometry);
padding = 0;
size = 0;
stretch = 0;
+ visible = false;
has_hfw = false;
done = false;
}
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,
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);
);
if( d.done )
- {
- _num_not_done -= 1;
continue;
- }
+ _num_not_done += 1;
if( d.stretch > 0 )
{
for(int i = 0; i < num_children; ++i)
{
ItemData& d = items[i];
+ if( !d.visible )
+ continue;
SG_LOG(
SG_GUI,
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
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]");
}
}
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) */
//----------------------------------------------------------------------------
LayoutItem::LayoutItem():
- _flags(0),
+ _flags(VISIBLE),
_size_hint(0, 0),
_min_size(0, 0),
_max_size(MAX_SIZE)
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()
{
_parent = parent;
LayoutItemRef parent_ref = parent.lock();
setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
+
+ setVisibleInternal(!parent_ref || parent_ref->isVisible());
}
//----------------------------------------------------------------------------
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
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.
*/
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;
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
);
}
+ //----------------------------------------------------------------------------
+ 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
virtual SGVec2i minimumSizeImpl() const;
virtual SGVec2i maximumSizeImpl() const;
+ virtual void visibilityChanged(bool visible);
+
};
typedef SGSharedPtr<NasalWidget> NasalWidgetRef;
#include "NasalWidget.hxx"
#include <simgear/debug/logstream.hxx>
+#include <simgear/nasal/cppbind/NasalContext.hxx>
+
#include <cstdlib>
//------------------------------------------------------------------------------
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:
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 )
{
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));
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));
}