X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fcanvas%2Frectangle.cc;h=64cdd3af8acedb78c52ee04cb744d03152bf2071;hb=00b8cff66fb971ead1a54e4b11e6dd869256461b;hp=0014958e909344aee4735666abf2152e642cffbe;hpb=a441de1a186e5521ad448aad0b201a278e7544a4;p=ardour.git diff --git a/libs/canvas/rectangle.cc b/libs/canvas/rectangle.cc index 0014958e90..64cdd3af8a 100644 --- a/libs/canvas/rectangle.cc +++ b/libs/canvas/rectangle.cc @@ -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 context context->rectangle (draw.x0, draw.y0, draw.width(), draw.height()); context->fill (); - } - + } + if (_outline) { 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 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 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()); }