X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fcanvas%2Frectangle.cc;h=232da178935b083720b8db64d2334087ee993eff;hb=f1e6b28ab7759f9bc93eb965cbe7740f1bafb2d3;hp=d90fd3a94335b61233b70aeb5a6751c3b434f41d;hpb=84f55440a3c6317dd2ab5d7e3d638016609e4d03;p=ardour.git diff --git a/libs/canvas/rectangle.cc b/libs/canvas/rectangle.cc index d90fd3a943..232da17893 100644 --- a/libs/canvas/rectangle.cc +++ b/libs/canvas/rectangle.cc @@ -30,86 +30,141 @@ using namespace std; using namespace ArdourCanvas; -Rectangle::Rectangle (Group* parent) - : Item (parent) - , Outline (parent) - , Fill (parent) +Rectangle::Rectangle (Canvas* c) + : Item (c) , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) { +} +Rectangle::Rectangle (Canvas* c, Rect const & rect) + : Item (c) + , _rect (rect) + , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) +{ } -Rectangle::Rectangle (Group* parent, Rect const & rect) +Rectangle::Rectangle (Item* parent) + : Item (parent) + , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) +{ +} + +Rectangle::Rectangle (Item* parent, Rect const & rect) : Item (parent) - , Outline (parent) - , Fill (parent) , _rect (rect) , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) { - +} + +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. + */ + + return item_to_window (_rect.translate (_position)); } void -Rectangle::render (Rect const & area, Cairo::RefPtr context) const +Rectangle::render_self (Rect const & area, Cairo::RefPtr context, Rect self) const { - Rect self = item_to_window (_rect); boost::optional r = self.intersection (area); if (!r) { - std::cerr << whatami() << '/' << name << " not covered by render area! ... " << self << " vs. " << area << std::endl; return; } Rect draw = r.get (); - if (_fill) { + if (_fill && !_transparent) { if (_stops.empty()) { setup_fill_context (context); } else { setup_gradient_context (context, self, Duple (draw.x0, draw.y0)); } + 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.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). + * + * 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. + */ + + self = self.translate (Duple (0.5, 0.5)); + + if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) { + + context->rectangle (self.x0, self.y0, self.width(), self.height()); - context->save (); - context->rectangle (draw.x0, draw.y0, draw.width(), draw.height()); - context->clip (); + } else { - if (_outline_what & LEFT) { - context->move_to (self.x0, self.y0); - context->line_to (self.x0, self.y1); - } - - if (_outline_what & BOTTOM) { - 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); - } - - if (_outline_what & TOP) { - context->move_to (self.x0, self.y0); - context->line_to (self.x1, self.y0); + if (_outline_what & LEFT) { + 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); + } + + if (_outline_what & BOTTOM) { + 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 (); - context->restore (); } } +void +Rectangle::render (Rect const & area, Cairo::RefPtr context) const +{ + render_self (area, context, get_self_for_render ()); +} + void Rectangle::compute_bounding_box () const { - Rect r = _rect.fix (); - _bounding_box = boost::optional (r.expand (_outline_width/2.0)); + 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 + */ + + r = r.expand (1.0); + + _bounding_box = r; + } + _bounding_box_dirty = false; } @@ -119,82 +174,111 @@ Rectangle::set (Rect const & r) /* We don't update the bounding box here; it's just as cheap to do it when asked. */ - - begin_change (); - - _rect = r; - - _bounding_box_dirty = true; - end_change (); - DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (set)\n"); + if (r != _rect) { + + begin_change (); + + _rect = r; + + _bounding_box_dirty = true; + end_change (); + } } void Rectangle::set_x0 (Coord x0) { - begin_change (); - - _rect.x0 = x0; - - _bounding_box_dirty = true; - end_change (); - - DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x0)\n"); + if (x0 != _rect.x0) { + begin_change (); + + _rect.x0 = x0; + + _bounding_box_dirty = true; + end_change (); + } } void Rectangle::set_y0 (Coord y0) { - begin_change (); - - _rect.y0 = y0; - - _bounding_box_dirty = true; - end_change(); - - DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y0)\n"); + if (y0 != _rect.y0) { + begin_change (); + + _rect.y0 = y0; + + _bounding_box_dirty = true; + end_change(); + } } void Rectangle::set_x1 (Coord x1) { - begin_change (); - - _rect.x1 = x1; - - _bounding_box_dirty = true; - end_change (); - - DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x1)\n"); + if (x1 != _rect.x1) { + begin_change (); + + _rect.x1 = x1; + + _bounding_box_dirty = true; + end_change (); + } } void Rectangle::set_y1 (Coord y1) { - begin_change (); - - _rect.y1 = y1; - - _bounding_box_dirty = true; - end_change (); - - DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y1)\n"); + if (y1 != _rect.y1) { + begin_change (); + + _rect.y1 = y1; + + _bounding_box_dirty = true; + end_change (); + } } void Rectangle::set_outline_what (What what) { - begin_change (); - - _outline_what = what; - - end_change (); + if (what != _outline_what) { + begin_visual_change (); + _outline_what = what; + end_visual_change (); + } } + +/*-------------------*/ + void -Rectangle::set_outline_what (int what) +TimeRectangle::compute_bounding_box () const { - set_outline_what ((What) what); + Rectangle::compute_bounding_box (); + + 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; + } } +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); +}