X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fcanvas%2Frectangle.cc;h=bc4ad0c9609862e34903d251a6b2fe458d33af65;hb=0622a0cc3068a06d328119e90b7d9c5f5a84df32;hp=38106a65506d1a358757e8048c0b24281a8a1424;hpb=54bf06e63cee78dfa218f604d862e577d0f5754c;p=ardour.git diff --git a/libs/canvas/rectangle.cc b/libs/canvas/rectangle.cc index 38106a6550..bc4ad0c960 100644 --- a/libs/canvas/rectangle.cc +++ b/libs/canvas/rectangle.cc @@ -30,110 +30,119 @@ 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 (Item* parent) + : Item (parent) + , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) +{ } -Rectangle::Rectangle (Group* parent, Rect const & rect) +Rectangle::Rectangle (Item* parent, Rect const & rect) : Item (parent) - , Outline (parent) - , Fill (parent) , _rect (rect) , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) { - } void -Rectangle::render (Rect const & /*area*/, Cairo::RefPtr context) const +Rectangle::render (Rect const & area, Cairo::RefPtr context) const { - /* Cairo goes a little (!) wrong when asked to fill/stroke rectangles that - * extend way beyond the surface boundaries. To avoid this issue, - * clamp what we are drawing using the absolute end of the visible - * canvas, converting to item-space coordinates, of course. - */ - - Rect plot = _rect; - Rect visible = _canvas->visible_area(); - Duple visible_end = canvas_to_item (Duple (visible.x1, visible.y1)); - - plot.x1 = min (plot.x1, visible_end.x); - plot.y1 = min (plot.y1, visible_end.y); - - if (_fill) { - setup_fill_context (context); - context->rectangle (plot.x0, plot.y0, plot.width(), plot.height()); - - if (!_outline) { - context->fill (); + /* 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)); + boost::optional r = self.intersection (area); + + if (!r) { + return; + } + + Rect draw = r.get (); + + if (_fill && !_transparent) { + if (_stops.empty()) { + setup_fill_context (context); } else { - - /* special/common case: outline the entire rectangle is - * requested, so just use the same path for the fill - * and stroke. - */ - - if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) { - context->fill_preserve(); - setup_outline_context (context); - context->stroke (); - } else { - context->fill (); - } + setup_gradient_context (context, self, Duple (draw.x0, draw.y0)); } + + context->rectangle (draw.x0, draw.y0, draw.width(), draw.height()); + context->fill (); } if (_outline) { - - if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) { - /* if we filled and use full outline, we are already done */ + setup_outline_context (context); + + /* see the cairo FAQ on single pixel lines to see why we do + * the 0.5 pixel additions. + */ - if (!_fill) { - context->rectangle (plot.x0, plot.y0, plot.width(), plot.height()); - setup_outline_context (context); - context->stroke (); - } + if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) { + context->rectangle (self.x0 + 0.5, self.y0 + 0.5, self.width() - 1.0, self.height() - 1.0); + } else { - + if (_outline_what & LEFT) { - context->move_to (plot.x0, plot.y0); - context->line_to (plot.x0, plot.y1); + /* vertical line: move x-coordinate by 0.5 pixels */ + context->move_to (self.x0 + 0.5, self.y0); + context->line_to (self.x0 + 0.5, self.y1); } + if (_outline_what & TOP) { + /* horizontal line: move y-coordinate by 0.5 pixels */ + context->move_to (self.x0, self.y0 + 0.5); + context->line_to (self.x1, self.y0 + 0.5); + } + if (_outline_what & BOTTOM) { - context->move_to (plot.x0, plot.y1); - context->line_to (plot.x1, plot.y1); + /* horizontal line: move y-coordinate by 0.5 pixels */ + context->move_to (self.x0, self.y1 - 0.5); + context->line_to (self.x1, self.y1 - 0.5); } if (_outline_what & RIGHT) { - context->move_to (plot.x1, plot.y0); - context->line_to (plot.x1, plot.y1); + /* vertical line: move x-coordinate by 0.5 pixels */ + context->move_to (self.x1 + 0.5, self.y0); + context->line_to (self.x1 + 0.5, self.y1); } - if (_outline_what & TOP) { - context->move_to (plot.x0, plot.y0); - context->line_to (plot.x1, plot.y0); - } - - setup_outline_context (context); - context->stroke (); } + + context->stroke (); } } void Rectangle::compute_bounding_box () const { - Rect r = _rect.fix (); - _bounding_box = boost::optional (r.expand (_outline_width / 2)); - + 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.x1 += 1.0; // XXX this makes no sense but is necessary + r.y1 += 0.5; + + _bounding_box = r; + } + _bounding_box_dirty = false; } @@ -143,82 +152,77 @@ 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 (); -} - -void -Rectangle::set_outline_what (int what) -{ - set_outline_what ((What) what); + if (what != _outline_what) { + begin_visual_change (); + _outline_what = what; + end_visual_change (); + } }