]> git.mxchange.org Git - simgear.git/commitdiff
CanvasImage: Fix border abs/rel calculations; add slice-width property
authorThomas Geymayer <tomgey@gmail.com>
Thu, 28 Feb 2013 00:09:27 +0000 (01:09 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 28 Feb 2013 00:09:27 +0000 (01:09 +0100)
simgear/canvas/elements/CanvasImage.cxx
simgear/canvas/elements/CanvasImage.hxx

index 3539cd4a2f4100bcbec3abfe2a81f75c8d242589..9787b23200e45775fa699bbe41da2e6fa52cb5d3 100644 (file)
@@ -21,6 +21,7 @@
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasMgr.hxx>
 #include <simgear/canvas/CanvasSystemAdapter.hxx>
+#include <simgear/canvas/MouseEvent.hxx>
 #include <simgear/scene/util/parse_color.hxx>
 #include <simgear/misc/sg_path.hxx>
 
@@ -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<float> 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<int>& 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<int>& 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<int>& dim = getTextureDimensions();
+      return CSSBorder();
 
     // [<number>'%'?]{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<boost::char_separator<char> > tokenizer;
     const boost::char_separator<char> 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<float>
             (
               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;
   }
index 127eece6d9f550e13860b80c0bdf5121d8bce6fb..39813e343d75b7a89e37d3e42e75a053f769c3d9 100644 (file)
@@ -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<float>& 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<int>& dim) const;
+        CSSOffsets getAbsOffsets(const SGRect<int>& 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<osg::Texture2D> _texture;
       // TODO optionally forward events to canvas
@@ -117,7 +141,8 @@ namespace canvas
       SGRect<float>   _src_rect,
                       _region;
 
-      CSSOffsets      _slice,
+      CSSBorder       _slice,
+                      _slice_width,
                       _outset;
   };