Fix some capitalisation in the preferences dialog.
[ardour.git] / libs / canvas / canvas.cc
index 313c9f7ae5f3e226508e44f570b776c4d630e73a..d5d85623612c33f8bbe1a54ca28fada03a5c49b2 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "canvas/canvas.h"
 #include "canvas/debug.h"
+#include "canvas/line.h"
 
 using namespace std;
 using namespace ArdourCanvas;
@@ -69,7 +70,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
 {
 #ifdef CANVAS_DEBUG
        if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
-               cerr << "RENDER: " << area << endl;
+               cerr << this << " RENDER: " << area << endl;
                //cerr << "CANVAS @ " << this << endl;
                //dump (cerr);
                //cerr << "-------------------------\n";
@@ -195,8 +196,12 @@ Duple
 Canvas::canvas_to_window (Duple const & d) const
 {
        Duple wd = d.translate (Duple (-_scroll_offset_x, -_scroll_offset_y));
+
+       /* Note that this intentionally always returns integer coordinates */
+
        wd.x = round (wd.x);
        wd.y = round (wd.y);
+
        return wd;
 }      
 
@@ -210,10 +215,14 @@ Rect
 Canvas::canvas_to_window (Rect const & r) const
 {
        Rect wr = r.translate (Duple (-_scroll_offset_x, -_scroll_offset_y));
-       wr.x0 = floor (wr.x0);
-       wr.x1 = ceil (wr.x1);
-       wr.y0 = floor (wr.y0);
-       wr.y1 = ceil (wr.y1);
+
+       /* Note that this intentionally always returns integer coordinates */
+
+       wr.x0 = round (wr.x0);
+       wr.x1 = round (wr.x1);
+       wr.y0 = round (wr.y0);
+       wr.y1 = round (wr.y1);
+
        return wr;
 }      
 
@@ -253,7 +262,7 @@ void
 Canvas::queue_draw_item_area (Item* item, Rect area)
 {
        ArdourCanvas::Rect canvas_area = item->item_to_canvas (area);
-       // cerr << "CANVAS " << this << " for " << item->whatami() << ' ' << item->name << " invalidate " << area << " TRANSLATE AS " << canvas_area << endl;
+       // cerr << "CANVAS " << this << " for " << item << ' ' << item->whatami() << ' ' << item->name << " invalidate " << area << " TRANSLATE AS " << canvas_area << " window = " << canvas_to_window (canvas_area) << std::endl;
        request_redraw (canvas_area);
 }
 
@@ -303,6 +312,20 @@ GtkCanvas::pick_current_item (Duple const & point, int state)
        vector<Item const *> items;
        _root.add_items_at_point (point, items);
 
+       DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("%1 covers %2 items\n", point, items.size()));
+
+#ifndef NDEBUG
+       if (DEBUG_ENABLED(PBD::DEBUG::CanvasEnterLeave)) {
+               for (vector<Item const*>::const_iterator it = items.begin(); it != items.end(); ++it) {
+#ifdef CANVAS_DEBUG
+                       std::cerr << "\tItem " << (*it)->whatami() << '/' << (*it)->name << std::endl;
+#else
+                       std::cerr << "\tItem " << (*it)->whatami() << std::endl;
+#endif
+               }
+       }
+#endif
+
        /* put all items at point that are event-sensitive and visible and NOT
           groups into within_items. Note that items is sorted from bottom to
           top, but we're going to reverse that for within_items so that its
@@ -328,17 +351,21 @@ GtkCanvas::pick_current_item (Duple const & point, int state)
        if (within_items.empty()) {
 
                /* no items at point, just send leave event below */
+               _new_current_item = 0;
 
        } else {
+
                if (within_items.front() == _current_item) {
                        /* uppermost item at point is already _current_item */
                        return;
                }
-               
+       
                _new_current_item = const_cast<Item*> (within_items.front());
        }
 
-       deliver_enter_leave (point, state);
+       if (_new_current_item != _current_item) {
+               deliver_enter_leave (point, state);
+       }
 }
 
 void
@@ -396,7 +423,7 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
        } else if (_current_item->is_descendant_of (*_new_current_item)) {
 
                /* move from descendant to ancestor (X: "_current_item is an
-                * inferior of _new_current_item") 
+                * inferior ("child") of _new_current_item") 
                 *
                 * Deliver "virtual" leave notifications to all items in the
                 * heirarchy between current and new_current.
@@ -413,7 +440,7 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
 
        } else if (_new_current_item->is_descendant_of (*_current_item)) {
                /* move from ancestor to descendant (X: "_new_current_item is
-                * an inferior of _current_item")
+                * an inferior ("child") of _current_item")
                 *
                 * Deliver "virtual" enter notifications to all items in the
                 * heirarchy between current and new_current.
@@ -454,7 +481,7 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
        if (_current_item && !_current_item->ignore_events ()) {
                leave_event.detail = leave_detail;
                _current_item->Event ((GdkEvent*)&leave_event);
-               // std::cerr << "LEAVE " << _current_item->whatami() << '/' << _current_item->name << std::endl;
+               DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("LEAVE %1/%2\n", _current_item->whatami(), _current_item->name));
        }
 
        leave_event.detail = GDK_NOTIFY_VIRTUAL;
@@ -462,13 +489,14 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
 
        for (vector<Item*>::iterator it = items_to_leave_virtual.begin(); it != items_to_leave_virtual.end(); ++it) {
                if (!(*it)->ignore_events()) {
+                       DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("leave %1/%2\n", (*it)->whatami(), (*it)->name));
                        (*it)->Event ((GdkEvent*)&leave_event);
-                       // std::cerr << "leave " << (*it)->whatami() << '/' << (*it)->name << std::endl;
                }
        }
 
        for (vector<Item*>::iterator it = items_to_enter_virtual.begin(); it != items_to_enter_virtual.end(); ++it) {
                if (!(*it)->ignore_events()) {
+                       DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("enter %1/%2\n", (*it)->whatami(), (*it)->name));
                        (*it)->Event ((GdkEvent*)&enter_event);
                        // std::cerr << "enter " << (*it)->whatami() << '/' << (*it)->name << std::endl;
                }
@@ -476,8 +504,8 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
 
        if (_new_current_item && !_new_current_item->ignore_events()) {
                enter_event.detail = enter_detail;
+               DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("ENTER %1/%2\n", _new_current_item->whatami(), _new_current_item->name));
                _new_current_item->Event ((GdkEvent*)&enter_event);
-               // std::cerr << "ENTER " << _new_current_item->whatami() << '/' << _new_current_item->name << std::endl;
        }
 
        _current_item = _new_current_item;
@@ -494,20 +522,24 @@ GtkCanvas::deliver_event (GdkEvent* event)
 {
        /* Point in in canvas coordinate space */
 
+       const Item* event_item;
+
        if (_grabbed_item) {
                /* we have a grabbed item, so everything gets sent there */
                DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("%1 %2 (%3) was grabbed, send event there\n",
                                                                       _grabbed_item, _grabbed_item->whatami(), _grabbed_item->name));
-               return _grabbed_item->Event (event);
+               event_item = _grabbed_item;
+       } else {
+               event_item = _current_item;
        }
 
-       if (!_current_item) {
+       if (!event_item) {
                return false;
        }
 
        /* run through the items from child to parent, until one claims the event */
 
-       Item* item = const_cast<Item*> (_current_item);
+       Item* item = const_cast<Item*> (event_item);
        
        while (item) {
 
@@ -524,7 +556,7 @@ GtkCanvas::deliver_event (GdkEvent* event)
                        return true;
                }
                
-               DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event left unhandled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name));
+               DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event %3 left unhandled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name, event_type_string (event->type)));
 
                if ((item = parent) == 0) {
                        break;
@@ -546,17 +578,10 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
                queue_draw_item_area (item, bounding_box.get ());
        }
        
-       /* no need to send a leave event to this item, since it is going away 
-        */
-
        if (_new_current_item == item) {
                _new_current_item = 0;
        }
 
-       if (_current_item == item) {
-               _current_item = 0;
-       }
-
        if (_grabbed_item == item) {
                _grabbed_item = 0;
        }
@@ -565,7 +590,12 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
                _focused_item = 0;
        }
 
-       pick_current_item (0); // no mouse state
+       if (_current_item == item) {
+               /* no need to send a leave event to this item, since it is going away 
+                */
+               _current_item = 0;
+               pick_current_item (0); // no mouse state
+       }
        
 }
 
@@ -576,10 +606,8 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
 bool
 GtkCanvas::on_expose_event (GdkEventExpose* ev)
 {
-       Cairo::RefPtr<Cairo::Context> c = get_window()->create_cairo_context ();
-
-       render (Rect (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height), c);
-
+       Cairo::RefPtr<Cairo::Context> cairo_context = get_window()->create_cairo_context ();
+       render (Rect (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height), cairo_context);
        return true;
 }
 
@@ -666,15 +694,6 @@ GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
 
        // DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas motion @ %1, %2\n", ev->x, ev->y));
 
-       if (_grabbed_item) {
-               /* if we have a grabbed item, it gets just the motion event,
-                  since no enter/leave events can have happened.
-               */
-               DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("%1 %2 (%3) was grabbed, send MOTION event there\n",
-                                                                      _grabbed_item, _grabbed_item->whatami(), _grabbed_item->name));
-               return _grabbed_item->Event (reinterpret_cast<GdkEvent*> (&copy));
-       }
-
        pick_current_item (where, ev->state);
 
        /* Now deliver the motion event.  It may seem a little inefficient
@@ -709,8 +728,13 @@ GtkCanvas::on_leave_notify_event (GdkEventCrossing* ev)
 void
 GtkCanvas::request_redraw (Rect const & request)
 {
-       Rect area = canvas_to_window (request);
-       queue_draw_area (area.x0, area.y0, area.width(), area.height());
+       boost::optional<Rect> req = request.intersection (visible_area());
+
+       if (req) {
+               Rect r = req.get();
+               Rect area = canvas_to_window (r);
+               queue_draw_area (area.x0, area.y0, area.width(), area.height());
+       }
 }
 
 /** Called to request that we try to get a particular size for ourselves.