Canvas: fix property inheritance.

- Do not override style of children if they have own values set.
 - Retrieve style of parent if own style value has been removed.
This commit is contained in:
Thomas Geymayer 2013-07-02 22:42:46 +02:00
parent 6f7c0c23d1
commit 6962de4b1f
6 changed files with 128 additions and 48 deletions

View File

@ -21,6 +21,7 @@
#include <simgear/canvas/CanvasEventListener.hxx> #include <simgear/canvas/CanvasEventListener.hxx>
#include <simgear/canvas/CanvasEventVisitor.hxx> #include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/MouseEvent.hxx> #include <simgear/canvas/MouseEvent.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/scene/material/parseBlendFunc.hxx> #include <simgear/scene/material/parseBlendFunc.hxx>
#include <osg/Drawable> #include <osg/Drawable>
@ -315,29 +316,38 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child) void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
{ {
if( parent == _node && child->getNameString() == NAME_TRANSFORM ) if( parent == _node )
{ {
if( !_transform.valid() ) if( child->getNameString() == NAME_TRANSFORM )
return;
if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
{ {
SG_LOG if( !_transform.valid() )
( return;
SG_GENERAL,
SG_WARN, if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
"Element::childRemoved: unknown transform: " << child->getPath() {
); SG_LOG
(
SG_GENERAL,
SG_WARN,
"Element::childRemoved: unknown transform: " << child->getPath()
);
return;
}
_transform_types[ child->getIndex() ] = TT_NONE;
while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
_transform_types.pop_back();
_transform_dirty = true;
return;
}
else if( StyleSetter const* setter =
getStyleSetter(child->getNameString()) )
{
setStyle(getParentStyle(child), setter);
return; return;
} }
_transform_types[ child->getIndex() ] = TT_NONE;
while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
_transform_types.pop_back();
_transform_dirty = true;
return;
} }
childRemoved(child); childRemoved(child);
@ -350,8 +360,17 @@ namespace canvas
if( parent == _node ) if( parent == _node )
{ {
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
if( setStyle(child) ) if( StyleSetter const* setter = getStyleSetter(name) )
{
SGPropertyNode const* style = child;
if( isStyleEmpty(child) )
{
child->clearValue();
style = getParentStyle(child);
}
setStyle(style, setter);
return; return;
}
else if( name == "update" ) else if( name == "update" )
return update(0); return update(0);
else if( name == "visible" ) else if( name == "visible" )
@ -371,21 +390,10 @@ namespace canvas
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool Element::setStyle(const SGPropertyNode* child) bool Element::setStyle( const SGPropertyNode* child,
const StyleSetter* setter )
{ {
StyleSetters::const_iterator setter = return canApplyStyle(child) && setStyleImpl(child, setter);
_style_setters.find(child->getNameString());
if( setter == _style_setters.end() )
return false;
const StyleSetter* style_setter = &setter->second.setter;
while( style_setter )
{
if( style_setter->func(*this, child) )
return true;
style_setter = style_setter->next;
}
return false;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -516,6 +524,67 @@ namespace canvas
} }
} }
//----------------------------------------------------------------------------
bool Element::isStyleEmpty(const SGPropertyNode* child) const
{
return !child
|| simgear::strutils::strip(child->getStringValue()).empty();
}
//----------------------------------------------------------------------------
bool Element::canApplyStyle(const SGPropertyNode* child) const
{
if( _node == child->getParent() )
return true;
// Parent values do not override if element has own value
return isStyleEmpty( _node->getChild(child->getName()) );
}
//----------------------------------------------------------------------------
bool Element::setStyleImpl( const SGPropertyNode* child,
const StyleSetter* setter )
{
const StyleSetter* style_setter = setter
? setter
: getStyleSetter(child->getNameString());
while( style_setter )
{
if( style_setter->func(*this, child) )
return true;
style_setter = style_setter->next;
}
return false;
}
//----------------------------------------------------------------------------
const Element::StyleSetter*
Element::getStyleSetter(const std::string& name) const
{
StyleSetters::const_iterator setter = _style_setters.find(name);
if( setter == _style_setters.end() )
return 0;
return &setter->second.setter;
}
//----------------------------------------------------------------------------
const SGPropertyNode*
Element::getParentStyle(const SGPropertyNode* child) const
{
// Try to get value from parent...
if( _parent )
{
Style::const_iterator style =
_parent->_style.find(child->getNameString());
if( style != _parent->_style.end() )
return style->second;
}
// ...or reset to default if none is available
return child; // TODO somehow get default value for each style?
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setDrawable( osg::Drawable* drawable ) void Element::setDrawable( osg::Drawable* drawable )
{ {

View File

@ -117,7 +117,8 @@ namespace canvas
SGPropertyNode * child ); SGPropertyNode * child );
virtual void valueChanged(SGPropertyNode * child); virtual void valueChanged(SGPropertyNode * child);
virtual bool setStyle(const SGPropertyNode* child); virtual bool setStyle( const SGPropertyNode* child,
const StyleSetter* setter = 0 );
/** /**
* Set clipping shape * Set clipping shape
@ -441,6 +442,14 @@ namespace canvas
); );
} }
bool isStyleEmpty(const SGPropertyNode* child) const;
bool canApplyStyle(const SGPropertyNode* child) const;
bool setStyleImpl( const SGPropertyNode* child,
const StyleSetter* setter = 0 );
const StyleSetter* getStyleSetter(const std::string& name) const;
const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const;
virtual void childAdded(SGPropertyNode * child) {} virtual void childAdded(SGPropertyNode * child) {}
virtual void childRemoved(SGPropertyNode * child){} virtual void childRemoved(SGPropertyNode * child){}
virtual void childChanged(SGPropertyNode * child){} virtual void childChanged(SGPropertyNode * child){}

View File

@ -174,20 +174,20 @@ namespace canvas
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool Group::setStyle(const SGPropertyNode* style) bool Group::setStyle( const SGPropertyNode* style,
const StyleSetter* setter )
{ {
// Don't propagate styles directly applicable to this group if( !canApplyStyle(style) )
if( Element::setStyle(style) )
return true;
if( style->getParent() != _node
&& _style.find(style->getNameString()) != _style.end() )
return false; return false;
// Don't propagate styles directly applicable to this group
if( setStyleImpl(style, setter) )
return true;
bool handled = false; bool handled = false;
for(size_t i = 0; i < _transform->getNumChildren(); ++i) for(size_t i = 0; i < _transform->getNumChildren(); ++i)
{ {
if( getChildByIndex(i)->setStyle(style) ) if( getChildByIndex(i)->setStyle(style, setter) )
handled = true; handled = true;
} }

View File

@ -92,7 +92,8 @@ namespace canvas
virtual bool traverse(EventVisitor& visitor); virtual bool traverse(EventVisitor& visitor);
virtual bool setStyle(const SGPropertyNode* child); virtual bool setStyle( const SGPropertyNode* child,
const StyleSetter* setter = 0 );
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;

View File

@ -400,8 +400,9 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Image::setFill(const std::string& fill) void Image::setFill(const std::string& fill)
{ {
osg::Vec4 color; osg::Vec4 color(1,1,1,1);
if( !parseColor(fill, color) ) if( !fill.empty() // If no color is given default to white
&& !parseColor(fill, color) )
return; return;
_colors->front() = color; _colors->front() = color;

View File

@ -110,7 +110,7 @@ namespace canvas
*/ */
void setFill(const std::string& fill) void setFill(const std::string& fill)
{ {
if( fill == "none" ) if( fill.empty() || fill == "none" )
{ {
_mode &= ~VG_FILL_PATH; _mode &= ~VG_FILL_PATH;
} }
@ -150,7 +150,7 @@ namespace canvas
*/ */
void setStroke(const std::string& stroke) void setStroke(const std::string& stroke)
{ {
if( stroke == "none" ) if( stroke.empty() || stroke == "none" )
{ {
_mode &= ~VG_STROKE_PATH; _mode &= ~VG_STROKE_PATH;
} }