fix crash when copy'ing latent plugins
[ardour.git] / libs / canvas / arrow.cc
index 5a48375bb8760090a2145aabef8eb10537c1f25b..1f8f5b44ec19ea2a66e36f6abd68121e8baa775d 100644 (file)
  *  @brief Implementation of the Arrow canvas object.
  */
 
+#include "pbd/compose.h"
+
 #include "canvas/arrow.h"
+#include "canvas/debug.h"
 #include "canvas/polygon.h"
 #include "canvas/line.h"
 
@@ -31,22 +34,51 @@ using namespace ArdourCanvas;
 /** Construct an Arrow.
  *  @param parent Parent canvas group.
  */
-Arrow::Arrow (Group* parent)
-       : Group (parent)
+Arrow::Arrow (Canvas* c)
+       : Container (c)
+{
+       setup ();
+}
+
+Arrow::Arrow (Item* parent)
+       : Container (parent)
 {
-       assert (parent);
+       setup ();
+}
 
+void
+Arrow::setup ()
+{
        /* set up default arrow heads at each end */
        for (int i = 0; i < 2; ++i) {
                _heads[i].polygon = new Polygon (this);
-               _heads[i].show = true;
                _heads[i].outward = true;
                _heads[i].width = 4;
                _heads[i].height = 4;
                setup_polygon (i);
+               CANVAS_DEBUG_NAME (_heads[i].polygon, string_compose ("arrow head %1", i));
        }
-       
+
        _line = new Line (this);
+       CANVAS_DEBUG_NAME (_line, "arrow line");
+}
+
+void
+Arrow::compute_bounding_box () const
+{
+       /* Compute our bounding box manually rather than using the default
+          container algorithm, since having the bounding box with origin other
+          than zero causes strange problems for mysterious reasons. */
+
+       const double outline_pad = 0.5 + (_line->outline_width() / 2.0);
+       const double head_width  = std::max(_heads[0].width, _heads[1].width);
+
+       _bounding_box = Rect(0,
+                            0,
+                            _line->x1() + (head_width / 2.0) + outline_pad,
+                            _line->y1());
+
+       _bounding_box_dirty = false;
 }
 
 /** Set whether to show an arrow head at one end or other
@@ -58,12 +90,16 @@ void
 Arrow::set_show_head (int which, bool show)
 {
        assert (which == 0 || which == 1);
-       
+
        begin_change ();
-       
-       _heads[which].show = show;
 
-       setup_polygon (which);
+       if (!show) {
+               delete _heads[which].polygon;
+               _heads[which].polygon = 0;
+       } else {
+               setup_polygon (which);
+       }
+
        _bounding_box_dirty = true;
        end_change ();
 }
@@ -78,7 +114,7 @@ void
 Arrow::set_head_outward (int which, bool outward)
 {
        assert (which == 0 || which == 1);
-       
+
        begin_change ();
 
        _heads[which].outward = outward;
@@ -96,9 +132,9 @@ void
 Arrow::set_head_height (int which, Distance height)
 {
        assert (which == 0 || which == 1);
-       
+
        begin_change ();
-       
+
        _heads[which].height = height;
 
        setup_polygon (which);
@@ -114,9 +150,9 @@ void
 Arrow::set_head_width (int which, Distance width)
 {
        assert (which == 0 || which == 1);
-       
+
        begin_change ();
-       
+
        _heads[which].width = width;
 
        setup_polygon (which);
@@ -131,8 +167,13 @@ void
 Arrow::set_outline_width (Distance width)
 {
        _line->set_outline_width (width);
-       _heads[0].polygon->set_outline_width (width);
-       _heads[1].polygon->set_outline_width (width);
+       if (_heads[0].polygon) {
+               _heads[0].polygon->set_outline_width (width);
+       }
+       if (_heads[1].polygon) {
+               _heads[1].polygon->set_outline_width (width);
+       }
+       _bounding_box_dirty = true;
 }
 
 /** Set the x position of our line.
@@ -144,9 +185,11 @@ Arrow::set_x (Coord x)
        _line->set_x0 (x);
        _line->set_x1 (x);
        for (int i = 0; i < 2; ++i) {
-               _heads[i].polygon->set_x_position (x - _heads[i].width / 2);
+               if (_heads[i].polygon) {
+                       _heads[i].polygon->set_x_position (x - _heads[i].width / 2);
+               }
        }
-               
+       _bounding_box_dirty = true;
 }
 
 /** Set the y position of end 0 of our line.
@@ -156,7 +199,10 @@ void
 Arrow::set_y0 (Coord y0)
 {
        _line->set_y0 (y0);
-       _heads[0].polygon->set_y_position (y0);
+       if (_heads[0].polygon) {
+               _heads[0].polygon->set_y_position (y0);
+       }
+       _bounding_box_dirty = true;
 }
 
 /** Set the y position of end 1 of our line.
@@ -166,7 +212,10 @@ void
 Arrow::set_y1 (Coord y1)
 {
        _line->set_y1 (y1);
-       _heads[1].polygon->set_y_position (y1 - _heads[1].height);
+       if (_heads[1].polygon) {
+               _heads[1].polygon->set_y_position (y1 - _heads[1].height);
+       }
+       _bounding_box_dirty = true;
 }
 
 /** @return x position of our line in pixels (in our coordinate system) */
@@ -190,7 +239,7 @@ void
 Arrow::setup_polygon (int which)
 {
        assert (which == 0 || which == 1);
-       
+
        Points points;
 
        if ((which == 0 && _heads[which].outward) || (which == 1 && !_heads[which].outward)) {
@@ -203,6 +252,7 @@ Arrow::setup_polygon (int which)
                points.push_back (Duple (0, 0));
                points.push_back (Duple (_heads[which].width, 0));
                points.push_back (Duple (_heads[which].width / 2, _heads[which].height));
+               points.push_back (Duple (0, 0));
        }
 
        _heads[which].polygon->set (points);
@@ -216,7 +266,26 @@ Arrow::set_color (Color color)
 {
        _line->set_outline_color (color);
        for (int i = 0; i < 2; ++i) {
-               _heads[i].polygon->set_outline_color (color);
-               _heads[i].polygon->set_fill_color (color);
+               if (_heads[i].polygon) {
+                       _heads[i].polygon->set_outline_color (color);
+                       _heads[i].polygon->set_fill_color (color);
+               }
+       }
+}
+
+bool
+Arrow::covers (Duple const & point) const
+{
+       if (_heads[0].polygon && _heads[0].polygon->covers (point)) {
+               return true;
+       }
+       if (_line && _line->covers (point)) {
+               return true;
        }
+
+       if (_heads[1].polygon && _heads[1].polygon->covers (point)) {
+               return true;
+       }
+
+       return false;
 }