From e1302bcf174c20429b16da0f3a929784044316c0 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Thu, 28 Feb 2013 01:09:27 +0100 Subject: [PATCH] CanvasImage: Fix border abs/rel calculations; add slice-width property --- simgear/canvas/elements/CanvasImage.cxx | 130 ++++++++++++++++++------ simgear/canvas/elements/CanvasImage.hxx | 47 +++++++-- 2 files changed, 135 insertions(+), 42 deletions(-) diff --git a/simgear/canvas/elements/CanvasImage.cxx b/simgear/canvas/elements/CanvasImage.cxx index 3539cd4a..9787b232 100644 --- a/simgear/canvas/elements/CanvasImage.cxx +++ b/simgear/canvas/elements/CanvasImage.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -115,6 +116,7 @@ namespace canvas addStyle("fill", &Image::setFill, this); addStyle("slice", &Image::setSlice, this); + addStyle("slice-width", &Image::setSliceWidth, this); addStyle("outset", &Image::setOutset, this); setFill("#ffffff"); // TODO how should we handle default values? @@ -162,10 +164,11 @@ namespace canvas SGRect region = _region; if( _outset.valid ) { - region.t() -= _outset.t; - region.r() += _outset.r; - region.b() += _outset.b; - region.l() -= _outset.l; + const CSSOffsets& outset = _outset.getAbsOffsets(tex_dim); + region.t() -= outset.t; + region.r() += outset.r; + region.b() += outset.b; + region.l() -= outset.l; } if( !_slice.valid ) @@ -195,16 +198,18 @@ namespace canvas -------------------- - y[3] */ + const CSSOffsets& slice = + (_slice_width.valid ? _slice_width : _slice).getAbsOffsets(tex_dim); float x[4] = { region.l(), - region.l() + _slice.l * tex_dim.width(), - region.r() - _slice.r * tex_dim.width(), + region.l() + slice.l, + region.r() - slice.r, region.r() }; float y[4] = { region.t(), - region.t() + _slice.t * tex_dim.height(), - region.b() - _slice.b * tex_dim.height(), + region.t() + slice.t, + region.b() - slice.b, region.b() }; @@ -249,16 +254,17 @@ namespace canvas } else { + const CSSOffsets& slice = _slice.getRelOffsets(tex_dim); float x[4] = { src_rect.l(), - src_rect.l() + _slice.l, - src_rect.r() - _slice.r, + src_rect.l() + slice.l, + src_rect.r() - slice.r, src_rect.r() }; float y[4] = { src_rect.t(), - src_rect.t() - _slice.t, - src_rect.b() + _slice.b, + src_rect.t() - slice.t, + src_rect.b() + slice.b, src_rect.b() }; @@ -338,6 +344,13 @@ namespace canvas _attributes_dirty |= SRC_RECT | DEST_SIZE; } + //---------------------------------------------------------------------------- + void Image::setSliceWidth(const std::string& width) + { + _slice_width = parseSideOffsets(width); + _attributes_dirty |= DEST_SIZE; + } + //---------------------------------------------------------------------------- void Image::setOutset(const std::string& outset) { @@ -351,6 +364,57 @@ namespace canvas return _region; } + //---------------------------------------------------------------------------- + bool Image::handleMouseEvent(MouseEventPtr event) + { + CanvasPtr src_canvas = _src_canvas.lock(); + + if( !src_canvas ) + return false; + + if( _outset.valid ) + { + CSSOffsets outset = _outset.getAbsOffsets(getTextureDimensions()); + + event.reset( new MouseEvent(*event) ); + event->client_pos += osg::Vec2f(outset.l, outset.t); + event->client_pos.x() *= src_canvas->getViewWidth() + / (_region.width() + outset.l + outset.r); + event->client_pos.y() *= src_canvas->getViewHeight() + / (_region.height() + outset.t + outset.b); + } + + return src_canvas->handleMouseEvent(event); + } + + //---------------------------------------------------------------------------- + Image::CSSOffsets + Image::CSSBorder::getRelOffsets(const SGRect& dim) const + { + CSSOffsets ret; + for(int i = 0; i < 4; ++i) + { + ret.val[i] = offsets.val[i]; + if( !types.rel[i] ) + ret.val[i] /= (i & 1) ? dim.height() : dim.width(); + } + return ret; + } + + //---------------------------------------------------------------------------- + Image::CSSOffsets + Image::CSSBorder::getAbsOffsets(const SGRect& dim) const + { + CSSOffsets ret; + for(int i = 0; i < 4; ++i) + { + ret.val[i] = offsets.val[i]; + if( types.rel[i] ) + ret.val[i] *= (i & 1) ? dim.height() : dim.width(); + } + return ret; + } + //---------------------------------------------------------------------------- void Image::childChanged(SGPropertyNode* child) { @@ -511,12 +575,10 @@ namespace canvas } //---------------------------------------------------------------------------- - Image::CSSOffsets Image::parseSideOffsets(const std::string& str) const + Image::CSSBorder Image::parseSideOffsets(const std::string& str) const { if( str.empty() ) - return CSSOffsets(); - - const SGRect& dim = getTextureDimensions(); + return CSSBorder(); // ['%'?]{1,4} (top[,right[,bottom[,left]]]) // @@ -524,7 +586,7 @@ namespace canvas // image for the horizontal offsets, the height for vertical offsets. // Numbers represent pixels in the image. int c = 0; - CSSOffsets ret; + CSSBorder ret; typedef boost::tokenizer > tokenizer; const boost::char_separator del(" \t\n"); @@ -538,46 +600,52 @@ namespace canvas ret.keyword = *tok; else { - bool rel = (*tok->rbegin() == '%'); - ret.offsets[c] = + bool rel = ret.types.rel[c] = (*tok->rbegin() == '%'); + ret.offsets.val[c] = // Negative values are not allowed and values bigger than the size of - // the image are interpreted as ‘100%’. - std::max(0.f, - std::min(1.f, + // the image are interpreted as ‘100%’. TODO check max + std::max + ( + 0.f, boost::lexical_cast ( rel ? boost::make_iterator_range(tok->begin(), tok->end() - 1) : *tok ) / - ( - rel ? 100 - : (c & 1) ? dim.width() : dim.height() - ) - )); - + (rel ? 100 : 1) + ); ++c; } } // When four values are specified, they set the offsets on the top, right, // bottom and left sides in that order. + +#define CSS_COPY_VAL(dest, src)\ + {\ + ret.offsets.val[dest] = ret.offsets.val[src];\ + ret.types.rel[dest] = ret.types.rel[src];\ + } + if( c < 4 ) { if( c < 3 ) { if( c < 2 ) // if the right is missing, it is the same as the top. - ret.offsets[1] = ret.offsets[0]; + CSS_COPY_VAL(1, 0); // if the bottom is missing, it is the same as the top - ret.offsets[2] = ret.offsets[0]; + CSS_COPY_VAL(2, 0); } // If the left is missing, it is the same as the right - ret.offsets[3] = ret.offsets[1]; + CSS_COPY_VAL(3, 1); } +#undef CSS_COPY_VAL + ret.valid = true; return ret; } diff --git a/simgear/canvas/elements/CanvasImage.hxx b/simgear/canvas/elements/CanvasImage.hxx index 127eece6..39813e34 100644 --- a/simgear/canvas/elements/CanvasImage.hxx +++ b/simgear/canvas/elements/CanvasImage.hxx @@ -62,6 +62,17 @@ namespace canvas */ void setSlice(const std::string& slice); + /** + * Set image slice width. + * + * By default the size of the 9-scale grid is the same as specified + * with setSlice/"slice". Using this method allows setting values + * different to the size in the source image. + * + * @see http://www.w3.org/TR/css3-background/#border-image-width + */ + void setSliceWidth(const std::string& width); + /** * http://www.w3.org/TR/css3-background/#border-image-outset */ @@ -69,6 +80,8 @@ namespace canvas const SGRect& getRegion() const; + bool handleMouseEvent(MouseEventPtr event); + protected: enum ImageAttributes @@ -77,20 +90,31 @@ namespace canvas DEST_SIZE = SRC_RECT << 1 // Element size }; - struct CSSOffsets + union CSSOffsets + { + float val[4]; + struct { float t, r, b, l; }; + }; + + union CSSOffsetsTypes + { + bool rel[4]; + struct { bool t_rel, r_rel, b_rel, l_rel; }; + }; + + struct CSSBorder { - CSSOffsets(): + CSSBorder(): valid(false) {} - union - { - float offsets[4]; - struct { float t, r, b, l; }; - }; + CSSOffsets getRelOffsets(const SGRect& dim) const; + CSSOffsets getAbsOffsets(const SGRect& dim) const; - std::string keyword; - bool valid; + CSSOffsets offsets; + CSSOffsetsTypes types; + std::string keyword; + bool valid; }; virtual void childChanged(SGPropertyNode * child); @@ -101,7 +125,7 @@ namespace canvas void setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br); void setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br); - CSSOffsets parseSideOffsets(const std::string& str) const; + CSSBorder parseSideOffsets(const std::string& str) const; osg::ref_ptr _texture; // TODO optionally forward events to canvas @@ -117,7 +141,8 @@ namespace canvas SGRect _src_rect, _region; - CSSOffsets _slice, + CSSBorder _slice, + _slice_width, _outset; }; -- 2.39.5