set the CairoWidget focus handler; reset focus when the mouse pointer leaves the...
[ardour.git] / gtk2_ardour / editor_canvas.cc
index 73bc7d1884fe5a447c32035f6c634d07cdf7db11..3d763cbe568cdc7be7ddf85fcce6b9aee3d0abf3 100644 (file)
@@ -56,6 +56,7 @@
 
 using namespace std;
 using namespace ARDOUR;
+using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace Gtk;
 using namespace Glib;
@@ -68,6 +69,11 @@ Editor::initialize_canvas ()
        _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
        _track_canvas = _track_canvas_viewport->canvas ();
 
+       /* scroll group for items that should not automatically scroll
+        *  (e.g verbose cursor). It shares the canvas coordinate space.
+       */
+       no_scroll_group = new ArdourCanvas::Container (_track_canvas->root());
+
        ArdourCanvas::ScrollGroup* hsg; 
        ArdourCanvas::ScrollGroup* hg;
        ArdourCanvas::ScrollGroup* vg;
@@ -101,7 +107,7 @@ Editor::initialize_canvas ()
        }
 
        /*a group to hold global rects like punch/loop indicators */
-       global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
+       global_rect_group = new ArdourCanvas::Container (hv_scroll_group);
        CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
 
         transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
@@ -113,10 +119,10 @@ Editor::initialize_canvas ()
        transport_punch_range_rect->hide();
 
        /*a group to hold time (measure) lines */
-       time_line_group = new ArdourCanvas::Group (hv_scroll_group);
+       time_line_group = new ArdourCanvas::Container (hv_scroll_group);
        CANVAS_DEBUG_NAME (time_line_group, "time line group");
 
-       _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
+       _trackview_group = new ArdourCanvas::Container (hv_scroll_group);
        CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
        
        // used to show zoom mode active zooming
@@ -131,30 +137,30 @@ Editor::initialize_canvas ()
        /* a group to hold stuff while it gets dragged around. Must be the
         * uppermost (last) group with hv_scroll_group as a parent
         */
-       _drag_motion_group = new ArdourCanvas::Group (hv_scroll_group);                                                                                                                                     
+       _drag_motion_group = new ArdourCanvas::Container (hv_scroll_group);                                                                                                                                     
         CANVAS_DEBUG_NAME (_drag_motion_group, "Canvas Drag Motion");
 
        /* TIME BAR CANVAS */
        
-       _time_markers_group = new ArdourCanvas::Group (h_scroll_group);
+       _time_markers_group = new ArdourCanvas::Container (h_scroll_group);
        CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
 
-       cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
+       cd_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
        CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
        /* the vide is temporarily placed a the same location as the
           cd_marker_group, but is moved later.
        */
-       videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
+       videotl_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
        CANVAS_DEBUG_NAME (videotl_group, "videotl group");
-       marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
+       marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
        CANVAS_DEBUG_NAME (marker_group, "marker group");
-       transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
+       transport_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
        CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
-       range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
+       range_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
        CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
-       tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
+       tempo_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
        CANVAS_DEBUG_NAME (tempo_group, "tempo group");
-       meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
+       meter_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
        CANVAS_DEBUG_NAME (meter_group, "meter group");
 
        meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
@@ -413,7 +419,7 @@ Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, doub
        }
 
 
-       std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
+       std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos, false);
        if (tvp.first == 0) {
 
                /* drop onto canvas background: create new tracks */
@@ -511,14 +517,11 @@ Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
 
        ArdourCanvas::Rect scrolling_boundary;
        Gtk::Allocation alloc;
-       int cx, cy;
 
        if (from_headers) {
                alloc = controls_layout.get_allocation ();
        } else {        
                alloc = _track_canvas_viewport->get_allocation ();
-               cx = alloc.get_x();
-               cy = alloc.get_y();
 
                /* reduce height by the height of the timebars, which happens
                   to correspond to the position of the hv_scroll_group.
@@ -575,12 +578,12 @@ Editor::autoscroll_canvas ()
        Gdk::ModifierType mask;
        frameoffset_t dx = 0;
        bool no_stop = false;
-       bool y_motion = false;
 
        get_window()->get_pointer (x, y, mask);
 
        VisualChange vc;
        bool vertical_motion = false;
+       bool y_motion = false;
 
        if (autoscroll_horizontal_allowed) {
 
@@ -638,14 +641,14 @@ Editor::autoscroll_canvas ()
                        /* scroll to make higher tracks visible */
 
                        if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
-                               y_motion = scroll_up_one_track ();
+                               scroll_up_one_track ();
                                vertical_motion = true;
                        }
 
                } else if (y > autoscroll_boundary.y1) {
 
                        if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
-                               y_motion = scroll_down_one_track ();
+                               scroll_down_one_track ();
                                vertical_motion = true;
                        }
                }
@@ -799,26 +802,48 @@ Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
 }
 
 void
-Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
+Editor::ensure_time_axis_view_is_visible (TimeAxisView const & track, bool at_top)
 {
-       double begin = tav.y_position();
-       double v = vertical_adjustment.get_value ();
-
-       if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
-               /* try to put the TimeAxisView roughly central */
-               if (begin >= _visible_canvas_height/2.0) {
-                       begin -= _visible_canvas_height/2.0;
-               }
+       if (track.hidden()) {
+               return;
        }
 
-       /* Clamp the y pos so that we do not extend beyond the canvas full
-        * height. 
+       /* compute visible area of trackview group, as offsets from top of
+        * trackview group.
         */
-       if (_full_canvas_height - begin < _visible_canvas_height){
-               begin = _full_canvas_height - _visible_canvas_height;
+
+       double const current_view_min_y = vertical_adjustment.get_value();
+       double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
+
+       double const track_min_y = track.y_position ();
+       double const track_max_y = track.y_position () + track.effective_height ();
+
+       if (!at_top && 
+           (track_min_y >= current_view_min_y &&
+            track_max_y < current_view_max_y)) {
+               /* already visible, and caller did not ask to place it at the
+                * top of the track canvas
+                */
+               return;
+       }
+
+       double new_value;
+
+       if (at_top) {
+               new_value = track_min_y;
+       } else {
+               if (track_min_y < current_view_min_y) {
+                       // Track is above the current view
+                       new_value = track_min_y;
+               } else if (track_max_y > current_view_max_y) {
+                       // Track is below the current view
+                       new_value = track.y_position () + track.effective_height() - vertical_adjustment.get_page_size();
+               } else {
+                       new_value = track_min_y;
+               }
        }
 
-       vertical_adjustment.set_value (begin);
+       vertical_adjustment.set_value(new_value);
 }
 
 /** Called when the main vertical_adjustment has changed */
@@ -862,7 +887,6 @@ Editor::color_handler()
        bbt_ruler->set_outline_color (text);
        
        playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
-       _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
 
        meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
        meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
@@ -982,8 +1006,8 @@ Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
 
        Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
 
-       if (win) {
-               _track_canvas->get_window()->set_cursor (*cursor);
+       if (win && cursor) {
+               win->set_cursor (*cursor);
        }
 }
 
@@ -1089,6 +1113,10 @@ Editor::which_mode_cursor () const
                }
                break;
 
+       case MouseCut:
+               mode_cursor = _cursors->scissors;
+               break;
+                       
        case MouseObject:
                /* don't use mode cursor, pick a grabber cursor based on the item */
                break;
@@ -1153,7 +1181,7 @@ Editor::which_mode_cursor () const
 }
 
 Gdk::Cursor*
-Editor::which_region_cursor () const
+Editor::which_track_cursor () const
 {
        Gdk::Cursor* cursor = 0;
 
@@ -1164,11 +1192,9 @@ Editor::which_region_cursor () const
                case JOIN_OBJECT_RANGE_NONE:
                case JOIN_OBJECT_RANGE_OBJECT:
                        cursor = which_grabber_cursor ();
-                       cerr << "region use grabber\n";
                        break;
                case JOIN_OBJECT_RANGE_RANGE:
                        cursor = _cursors->selector;
-                       cerr << "region use selector\n";
                        break;
                }
        }
@@ -1198,8 +1224,6 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
 {
        Gdk::Cursor* cursor = 0;
 
-       cerr << "entered new item type " << enum_2_string (type) << endl;
-
        if (_drags->active()) {
                return;
        }
@@ -1215,7 +1239,9 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                case RegionViewNameHighlight:
                case RegionViewName:
                case WaveItem:
-                       cursor = which_region_cursor ();
+               case StreamItem:
+               case AutomationTrackItem:
+                       cursor = which_track_cursor ();
                        break;
                case PlayheadCursorItem:
                        switch (_edit_point) {
@@ -1240,11 +1266,10 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                        cursor = _cursors->cross_hair;
                        break;
                case StartSelectionTrimItem:
+                       cursor = _cursors->left_side_trim;
                        break;
                case EndSelectionTrimItem:
-                       break;
-               case AutomationTrackItem:
-                       cursor = _cursors->cross_hair;
+                       cursor = _cursors->right_side_trim;
                        break;
                case FadeInItem:
                        cursor = _cursors->fade_in;
@@ -1271,10 +1296,12 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                        cursor = _cursors->cross_hair;
                        break;
                case LeftFrameHandle:
-                       cursor = which_trim_cursor (true);
+                       if ( effective_mouse_mode() == MouseObject )  // (smart mode): if the user is in the top half, override the trim cursor, since they are in the range zone
+                               cursor = which_trim_cursor (true);  //alternatively, one could argue that we _should_ allow trims here, and disallow range selection
                        break;
                case RightFrameHandle:
-                       cursor = which_trim_cursor (false);
+                       if ( effective_mouse_mode() == MouseObject )  //see above
+                               cursor = which_trim_cursor (false);
                        break;
                case StartCrossFadeItem:
                        cursor = _cursors->fade_in;
@@ -1310,6 +1337,7 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
        case CdMarkerBarItem:
        case VideoBarItem:
        case TransportMarkerBarItem:
+       case DropZoneItem:
                cursor = which_grabber_cursor();
                break;
 
@@ -1321,3 +1349,13 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                set_canvas_cursor (cursor, false);
        }
 }
+
+double
+Editor::trackviews_height() const
+{
+       if (!_trackview_group) {
+               return 0;
+       }
+
+       return _visible_canvas_height - _trackview_group->canvas_origin().y;
+}