unused but slightly tricky code to add track name/instrument to an SMF file when...
[ardour.git] / libs / canvas / rectangle.cc
index 8ee83195919e9ef51c0be9efab46a707bddb142f..3158dad4ae102e6beb4a2d25c8733bb58879b59c 100644 (file)
@@ -56,15 +56,21 @@ Rectangle::Rectangle (Item* parent, Rect const & rect)
 {
 }
 
-void
-Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
+Rect
+Rectangle::get_self_for_render () const
 {
        /* In general, a Rectangle will have a _position of (0,0) within its
           parent, and its extent is actually defined by _rect. But in the
           unusual case that _position is set to something other than (0,0),
           we should take that into account when rendering.
        */
-       Rect self = item_to_window (_rect.translate (_position));
+
+       return item_to_window (_rect.translate (_position), false);
+}
+
+void
+Rectangle::render_self (Rect const & area, Cairo::RefPtr<Cairo::Context> context, Rect self) const
+{
        boost::optional<Rect> r = self.intersection (area);
 
        if (!r) {
@@ -82,35 +88,32 @@ Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) con
 
                context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
                context->fill ();
-       } 
-       
-       if (_outline) {
+       }
+
+       if (_outline && _outline_width && _outline_what) {
 
                setup_outline_context (context);
-               
+
                /* the goal here is that if the border is 1 pixel
                 * thick, it will precisely align with the corner
                 * coordinates of the rectangle. So if the rectangle
                 * has a left edge at 0 and a right edge at 10, then
-                * the left edge must span -0.5..+0.5, the right edge
-                * must span 9.5..10.5 (i.e. the single full color
-                * pixel is precisely aligned with 0 and 10
-                * respectively).
+                * the left edge must span 0..1, the right edge
+                * must span 10..11 because the first and final pixels
+                * to be colored are actually "at" 0.5 and 10.5 (midway
+                * between the integer coordinates).
                 *
-                * we have to shift left/up in all cases, which means
-                * subtraction along both axes (i.e. edge at
-                * N, outline must start at N-0.5). 
-                *
-                * see the cairo FAQ on single pixel lines to see why we do
-                * the 0.5 pixel additions.
+                * See the Cairo FAQ on single pixel lines for more
+                * detail.
                 */
 
-               self = self.translate (Duple (-0.5, -0.5));
+               if (fmod (_outline_width, 2.0)  != 0.0) {
+                       const double shift = _outline_width * 0.5;
+                       self = self.translate (Duple (shift, shift));
+               }
 
-               std::cerr << "Outline using " << self << " from " << _rect << std::endl;
-               
                if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
-                       
+
                        context->rectangle (self.x0, self.y0, self.width(), self.height());
 
                } else {
@@ -119,7 +122,7 @@ Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) con
                                context->move_to (self.x0, self.y0);
                                context->line_to (self.x0, self.y1);
                        }
-                       
+
                        if (_outline_what & TOP) {
                                context->move_to (self.x0, self.y0);
                                context->line_to (self.x1, self.y0);
@@ -129,30 +132,56 @@ Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) con
                                context->move_to (self.x0, self.y1);
                                context->line_to (self.x1, self.y1);
                        }
-                       
+
                        if (_outline_what & RIGHT) {
                                context->move_to (self.x1, self.y0);
                                context->line_to (self.x1, self.y1);
                        }
                }
-               
+
                context->stroke ();
        }
 }
 
+void
+Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
+{
+       render_self (area, context, get_self_for_render ());
+}
+
 void
 Rectangle::compute_bounding_box () const
 {
        if (!_rect.empty()) {
                Rect r = _rect.fix ();
 
-               /* take into acount the 0.5 addition to the bounding
-                  box for the right and bottom edges, see ::render() above
+               /* if the outline is 1 pixel, then the actual
+                  bounding box is 0.5 pixels outside the stated
+                  corners of the rectangle.
+
+                  if the outline is 2 pixels, then the actual
+                  bounding box is 1.0 pixels outside the stated
+                  corners of the rectangle (so that the middle
+                  of the 2 pixel wide border passes through
+                  the corners, alternatively described as 1 row
+                  of pixels outside of the corners, and 1 row
+                  inside).
+
+                  if the outline is 3 pixels, then the actual
+                  bounding box is 1.5 outside the stated corners
+                  of the rectangle (so that the middle row of
+                  pixels of the border passes through the corners).
+
+                  if the outline is 4 pixels, then the actual bounding
+                  box is 2.0 pixels outside the stated corners
+                  of the rectangle, so that the border consists
+                  of 2 pixels outside the corners and 2 pixels inside.
+
+                  hence ... the bounding box is width * 0.5 larger
+                  than the rectangle itself.
                */
 
-               r = r.expand (1.0);
-
-               _bounding_box = r;
+               _bounding_box = r.expand (1.0 + _outline_width * 0.5);
        }
 
        _bounding_box_dirty = false;
@@ -166,11 +195,11 @@ Rectangle::set (Rect const & r)
        */
 
        if (r != _rect) {
-               
+
                begin_change ();
-               
+
                _rect = r;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -181,9 +210,9 @@ Rectangle::set_x0 (Coord x0)
 {
        if (x0 != _rect.x0) {
                begin_change ();
-               
+
                _rect.x0 = x0;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -194,9 +223,9 @@ Rectangle::set_y0 (Coord y0)
 {
        if (y0 != _rect.y0) {
                begin_change ();
-               
+
                _rect.y0 = y0;
-               
+
                _bounding_box_dirty = true;
                end_change();
        }
@@ -207,9 +236,9 @@ Rectangle::set_x1 (Coord x1)
 {
        if (x1 != _rect.x1) {
                begin_change ();
-               
+
                _rect.x1 = x1;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -220,9 +249,9 @@ Rectangle::set_y1 (Coord y1)
 {
        if (y1 != _rect.y1) {
                begin_change ();
-               
+
                _rect.y1 = y1;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -238,3 +267,25 @@ Rectangle::set_outline_what (What what)
        }
 }
 
+double
+Rectangle::vertical_fraction (double y) const
+{
+        /* y is in canvas coordinates */
+
+        Duple i (canvas_to_item (Duple (0, y)));
+        boost::optional<Rect> r = bounding_box();
+        if (!r) {
+                return 0; /* not really correct, but what else can we do? */
+        }
+
+        Rect bbox (r.get());
+
+        if (i.y < bbox.y0 || i.y >= bbox.y1) {
+                return 0;
+        }
+
+        /* convert to fit Cairo origin model (origin at upper left)
+         */
+
+        return 1.0 - ((i.y - bbox.y0) / bbox.height());
+}