consolidate VST UI code
[ardour.git] / libs / canvas / rectangle.cc
index 0014958e909344aee4735666abf2152e642cffbe..3158dad4ae102e6beb4a2d25c8733bb58879b59c 100644 (file)
@@ -65,7 +65,7 @@ Rectangle::get_self_for_render () const
           we should take that into account when rendering.
        */
 
-       return item_to_window (_rect.translate (_position));
+       return item_to_window (_rect.translate (_position), false);
 }
 
 void
@@ -88,50 +88,57 @@ Rectangle::render_self (Rect const & area, Cairo::RefPtr<Cairo::Context> context
 
                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..1, the right edge
-                * must span 9..10 because the first and final pixels
-                * to be colored are actually "at" 0.5 and 9.5 (midway
-                * between the integer coordinates.
+                * 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).
+                *
+                * See the Cairo FAQ on single pixel lines for more
+                * detail.
                 */
 
+               if (fmod (_outline_width, 2.0)  != 0.0) {
+                       const double shift = _outline_width * 0.5;
+                       self = self.translate (Duple (shift, shift));
+               }
+
                if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
-                       
-                       self = self.shrink (0.5);
+
                        context->rectangle (self.x0, self.y0, self.width(), self.height());
 
                } else {
 
                        if (_outline_what & LEFT) {
-                               context->move_to (self.x0+0.5, self.y0);
-                               context->line_to (self.x0+0.5, self.y1);
+                               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+0.5);
-                               context->line_to (self.x1, self.y0+0.5);
+                               context->move_to (self.x0, self.y0);
+                               context->line_to (self.x1, self.y0);
                        }
 
                        if (_outline_what & BOTTOM) {
-                               context->move_to (self.x0, self.y1-0.5);
-                               context->line_to (self.x1, self.y1-0.5);
+                               context->move_to (self.x0, self.y1);
+                               context->line_to (self.x1, self.y1);
                        }
-                       
+
                        if (_outline_what & RIGHT) {
-                               context->move_to (self.x1-0.5, self.y0);
-                               context->line_to (self.x1-0.5, self.y1);
+                               context->move_to (self.x1, self.y0);
+                               context->line_to (self.x1, self.y1);
                        }
                }
-               
+
                context->stroke ();
        }
 }
@@ -147,7 +154,34 @@ Rectangle::compute_bounding_box () const
 {
        if (!_rect.empty()) {
                Rect r = _rect.fix ();
-               _bounding_box = r;
+
+               /* 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.
+               */
+
+               _bounding_box = r.expand (1.0 + _outline_width * 0.5);
        }
 
        _bounding_box_dirty = false;
@@ -161,11 +195,11 @@ Rectangle::set (Rect const & r)
        */
 
        if (r != _rect) {
-               
+
                begin_change ();
-               
+
                _rect = r;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -176,9 +210,9 @@ Rectangle::set_x0 (Coord x0)
 {
        if (x0 != _rect.x0) {
                begin_change ();
-               
+
                _rect.x0 = x0;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -189,9 +223,9 @@ Rectangle::set_y0 (Coord y0)
 {
        if (y0 != _rect.y0) {
                begin_change ();
-               
+
                _rect.y0 = y0;
-               
+
                _bounding_box_dirty = true;
                end_change();
        }
@@ -202,9 +236,9 @@ Rectangle::set_x1 (Coord x1)
 {
        if (x1 != _rect.x1) {
                begin_change ();
-               
+
                _rect.x1 = x1;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -215,9 +249,9 @@ Rectangle::set_y1 (Coord y1)
 {
        if (y1 != _rect.y1) {
                begin_change ();
-               
+
                _rect.y1 = y1;
-               
+
                _bounding_box_dirty = true;
                end_change ();
        }
@@ -233,36 +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());
 
-void
-TimeRectangle::compute_bounding_box () const
-{
-       Rectangle::compute_bounding_box ();
+        if (i.y < bbox.y0 || i.y >= bbox.y1) {
+                return 0;
+        }
 
-       if (_bounding_box) {
-               Rect r = _bounding_box.get ();
-               
-               /* This is a TimeRectangle, so its right edge is drawn 1 pixel beyond
-                * (larger x-axis coordinates) than a normal Rectangle.
-                */
-               
-               r.x1 += 1.0; /* this should be using safe_add() */
-               
-               _bounding_box = r;
-       }
-}
+        /* convert to fit Cairo origin model (origin at upper left)
+         */
 
-void 
-TimeRectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
-{
-       Rect self = get_self_for_render ();
-       
-       /* This is a TimeRectangle, so its right edge is drawn 1 pixel beyond
-        * (larger x-axis coordinates) than a normal Rectangle.
-        */
-
-       self.x1 += 1.0; /* this should be using safe_add() */
-       render_self (area, context, self);
+        return 1.0 - ((i.y - bbox.y0) / bbox.height());
 }