fix for previous checkin; should allow waves midi backend to work
[ardour.git] / gtk2_ardour / editor_canvas.cc
index 1bd6ba3d9e0f751e14a580242181431ad4cca2fa..c1929bd38bb2e664d6827b5b9fa194c3114411bf 100644 (file)
@@ -27,6 +27,8 @@
 #include "ardour/rc_configuration.h"
 #include "ardour/smf_source.h"
 
+#include "pbd/error.h"
+
 #include "canvas/canvas.h"
 #include "canvas/rectangle.h"
 #include "canvas/pixbuf.h"
@@ -69,7 +71,7 @@ Editor::initialize_canvas ()
        _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
        _track_canvas = _track_canvas_viewport->canvas ();
 
-        _track_canvas->set_background_color (ARDOUR_UI::config()->get_canvasvar_ArrangeBase());
+       _track_canvas->set_background_color (ARDOUR_UI::config()->color ("arrange base"));
 
        /* scroll group for items that should not automatically scroll
         *  (e.g verbose cursor). It shares the canvas coordinate space.
@@ -78,7 +80,11 @@ Editor::initialize_canvas ()
 
        ArdourCanvas::ScrollGroup* hsg; 
        ArdourCanvas::ScrollGroup* hg;
-       ArdourCanvas::ScrollGroup* vg;
+       ArdourCanvas::ScrollGroup* cg;
+
+       h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
+       CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
+       _track_canvas->add_scroller (*hg);
 
        hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), 
                                                               ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
@@ -86,13 +92,9 @@ Editor::initialize_canvas ()
        CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
        _track_canvas->add_scroller (*hsg);
 
-       v_scroll_group = vg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsVertically);
-       CANVAS_DEBUG_NAME (v_scroll_group, "canvas v scroll");
-       _track_canvas->add_scroller (*vg);
-
-       h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
-       CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
-       _track_canvas->add_scroller (*hg);
+       cursor_scroll_group = cg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
+       CANVAS_DEBUG_NAME (cursor_scroll_group, "canvas cursor scroll");
+       _track_canvas->add_scroller (*cg);
 
        _verbose_cursor = new VerboseCursor (this);
 
@@ -121,7 +123,7 @@ Editor::initialize_canvas ()
        transport_punch_range_rect->hide();
 
        /*a group to hold time (measure) lines */
-       time_line_group = new ArdourCanvas::Container (hv_scroll_group);
+       time_line_group = new ArdourCanvas::Container (h_scroll_group);
        CANVAS_DEBUG_NAME (time_line_group, "time line group");
 
        _trackview_group = new ArdourCanvas::Container (hv_scroll_group);
@@ -229,7 +231,6 @@ Editor::initialize_canvas ()
                logo_item->lower_to_bottom ();
        }
 
-
        _canvas_drop_zone = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 0.0));
        /* this thing is transparent */
        _canvas_drop_zone->set_fill (false);
@@ -367,8 +368,10 @@ Editor::reset_controls_layout_height (int32_t h)
 bool
 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
 {
-       if (current_canvas_cursor) {
-               set_canvas_cursor (current_canvas_cursor);
+       if (!_cursor_stack.empty()) {
+               set_canvas_cursor (get_canvas_cursor());
+       } else {
+               PBD::error << "cursor stack is empty" << endmsg;
        }
        return false;
 }
@@ -425,7 +428,7 @@ Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, doub
 
                do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
                
-               if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
+               if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files() || copy) {
                        do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
                } else {
                        do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
@@ -441,7 +444,7 @@ Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, doub
 
                        do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
 
-                       if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
+                       if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files() || copy) {
                                do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
                        } else {
                                do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
@@ -497,7 +500,7 @@ Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
 void
 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
 {
-       if (!Config->get_autoscroll_editor () || autoscroll_active ()) {
+       if (!ARDOUR_UI::config()->get_autoscroll_editor () || autoscroll_active ()) {
                return;
        }
 
@@ -778,6 +781,17 @@ Editor::stop_canvas_autoscroll ()
        autoscroll_connection.disconnect ();
 }
 
+Editor::EnterContext*
+Editor::get_enter_context(ItemType type)
+{
+       for (ssize_t i = _enter_stack.size() - 1; i >= 0; --i) {
+               if (_enter_stack[i].item_type == type) {
+                       return &_enter_stack[i];
+               }
+       }
+       return NULL;
+}
+
 bool
 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
 {
@@ -871,8 +885,8 @@ Editor::set_horizontal_position (double p)
 void
 Editor::color_handler()
 {
-       ArdourCanvas::Color base = ARDOUR_UI::config()->get_RulerBase();
-       ArdourCanvas::Color text = ARDOUR_UI::config()->get_RulerText();
+       ArdourCanvas::Color base = ARDOUR_UI::config()->color ("ruler base");
+       ArdourCanvas::Color text = ARDOUR_UI::config()->color ("ruler text");
        timecode_ruler->set_fill_color (base);
        timecode_ruler->set_outline_color (text);
        minsec_ruler->set_fill_color (base);
@@ -882,57 +896,58 @@ Editor::color_handler()
        bbt_ruler->set_fill_color (base);
        bbt_ruler->set_outline_color (text);
        
-       playhead_cursor->set_color (ARDOUR_UI::config()->get_PlayHead());
+       playhead_cursor->set_color (ARDOUR_UI::config()->color ("play head"));
 
-       meter_bar->set_fill_color (ARDOUR_UI::config()->get_MeterBar());
-       meter_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       meter_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("meter bar", "marker bar"));
+       meter_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       tempo_bar->set_fill_color (ARDOUR_UI::config()->get_TempoBar());
-       tempo_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       tempo_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("tempo bar", "marker bar"));
+       tempo_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       marker_bar->set_fill_color (ARDOUR_UI::config()->get_MarkerBar());
-       marker_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("marker bar", "marker bar"));
+       marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_CDMarkerBar());
-       cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       cd_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("cd marker bar", "marker bar"));
+       cd_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_RangeMarkerBar());
-       range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       range_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("range marker bar", "marker bar"));
+       range_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_TransportMarkerBar());
-       transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_MarkerBarSeparator());
+       transport_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("transport marker bar", "marker bar"));
+       transport_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
 
-       cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_RangeDragBarRect());
-       cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_RangeDragBarRect());
+       cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("range drag bar rect"));
+       cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("range drag bar rect"));
 
-       range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_RangeDragBarRect());
-       range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_RangeDragBarRect());
+       range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("range drag bar rect"));
+       range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("range drag bar rect"));
 
-       transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_TransportDragRect());
-       transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_TransportDragRect());
+       transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("transport drag rect"));
+       transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("transport drag rect"));
 
-       transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_TransportLoopRect());
-       transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_TransportLoopRect());
+       transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("transport loop rect", "loop rectangle"));
+       transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->color ("transport loop rect"));
 
-       transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_TransportPunchRect());
-       transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_TransportPunchRect());
+       transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->color ("transport punch rect"));
+       transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->color ("transport punch rect"));
 
-       transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_PunchLine());
-       transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_PunchLine());
+       transport_punchin_line->set_outline_color (ARDOUR_UI::config()->color ("punch line"));
+       transport_punchout_line->set_outline_color (ARDOUR_UI::config()->color ("punch line"));
 
-       rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_RubberBandRect());
-       rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_RubberBandRect());
+       rubberband_rect->set_outline_color (ARDOUR_UI::config()->color ("rubber band rect"));
+       rubberband_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("rubber band rect", "selection rect"));
 
-       location_marker_color = ARDOUR_UI::config()->get_LocationMarker();
-       location_range_color = ARDOUR_UI::config()->get_LocationRange();
-       location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
-       location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
-       location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
+       location_marker_color = ARDOUR_UI::config()->color ("location marker");
+       location_range_color = ARDOUR_UI::config()->color ("location range");
+       location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
+       location_loop_color = ARDOUR_UI::config()->color ("location loop");
+       location_punch_color = ARDOUR_UI::config()->color ("location punch");
 
        refresh_location_display ();
 
-        /* redraw the whole thing */
-        _track_canvas->queue_draw ();
+       /* redraw the whole thing */
+       _track_canvas->set_background_color (ARDOUR_UI::config()->color ("arrange base"));
+       _track_canvas->queue_draw ();
         
 /*
        redisplay_tempo (true);
@@ -985,36 +1000,57 @@ Editor::get_track_canvas() const
        return _track_canvas_viewport;
 }
 
-void
-Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
+Gdk::Cursor*
+Editor::get_canvas_cursor () const
 {
-       if (save) {
-               current_canvas_cursor = cursor;
-       }
+       /* The top of the cursor stack is always the currently visible cursor. */
+       return _cursor_stack.back();
+}
 
+void
+Editor::set_canvas_cursor (Gdk::Cursor* cursor)
+{
        Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
 
-       if (win && cursor) {
-               win->set_cursor (*cursor);
+       if (win && !_cursors->is_invalid (cursor)) {
+               /* glibmm 2.4 doesn't allow null cursor pointer because it uses
+                  a Gdk::Cursor& as the argument to Gdk::Window::set_cursor().
+                  But a null pointer just means "use parent window cursor",
+                  and so should be allowed. Gtkmm 3.x has fixed this API.
+
+                  For now, drop down and use C API
+               */
+               gdk_window_set_cursor (win->gobj(), cursor ? cursor->gobj() : 0);
        }
 }
 
-void
+size_t
 Editor::push_canvas_cursor (Gdk::Cursor* cursor)
 {
-       if (cursor) {
-               _cursor_stack.push (cursor);
-               set_canvas_cursor (cursor, false);
+       if (!_cursors->is_invalid (cursor)) {
+               _cursor_stack.push_back (cursor);
+               set_canvas_cursor (cursor);
        }
+       return _cursor_stack.size() - 1;
 }
 
 void
 Editor::pop_canvas_cursor ()
 {
-       if (!_cursor_stack.empty()) {
-               Gdk::Cursor* cursor = _cursor_stack.top ();
-               _cursor_stack.pop ();
-               set_canvas_cursor (cursor, false);
+       while (true) {
+               if (_cursor_stack.size() <= 1) {
+                       PBD::error << "attempt to pop default cursor" << endmsg;
+                       return;
+               }
+
+               _cursor_stack.pop_back();
+               if (_cursor_stack.back()) {
+                       /* Popped to an existing cursor, we're done.  Otherwise, the
+                          context that created this cursor has been destroyed, so we need
+                          to skip to the next down the stack. */
+                       set_canvas_cursor (_cursor_stack.back());
+                       return;
+               }
        }
 }
 
@@ -1023,41 +1059,16 @@ Editor::which_grabber_cursor () const
 {
        Gdk::Cursor* c = _cursors->grabber;
 
-       if (_internal_editing) {
-               switch (mouse_mode) {
-               case MouseDraw:
-                       c = _cursors->midi_pencil;
-                       break;
-
-               case MouseObject:
-                       c = _cursors->grabber_note;
-                       break;
-
-               case MouseTimeFX:
-                       c = _cursors->midi_resize;
-                       break;
-                       
-               case MouseRange:
-                       c = _cursors->grabber_note;
-                       break;
-
-               default:
-                       break;
-               }
-
-       } else {
-
-               switch (_edit_point) {
-               case EditAtMouse:
-                       c = _cursors->grabber_edit_point;
-                       break;
-               default:
-                       boost::shared_ptr<Movable> m = _movable.lock();
-                       if (m && m->locked()) {
-                               c = _cursors->speaker;
-                       }
-                       break;
+       switch (_edit_point) {
+       case EditAtMouse:
+               c = _cursors->grabber_edit_point;
+               break;
+       default:
+               boost::shared_ptr<Movable> m = _movable.lock();
+               if (m && m->locked()) {
+                       c = _cursors->speaker;
                }
+               break;
        }
 
        return c;
@@ -1091,14 +1102,11 @@ Editor::which_trim_cursor (bool left) const
 Gdk::Cursor*
 Editor::which_mode_cursor () const
 {
-       Gdk::Cursor* mode_cursor = 0;
+       Gdk::Cursor* mode_cursor = MouseCursors::invalid_cursor ();
 
        switch (mouse_mode) {
        case MouseRange:
                mode_cursor = _cursors->selector;
-               if (_internal_editing) {
-                       mode_cursor = which_grabber_cursor();
-               }
                break;
 
        case MouseCut:
@@ -1106,6 +1114,7 @@ Editor::which_mode_cursor () const
                break;
                        
        case MouseObject:
+       case MouseContent:
                /* don't use mode cursor, pick a grabber cursor based on the item */
                break;
 
@@ -1113,10 +1122,6 @@ Editor::which_mode_cursor () const
                mode_cursor = _cursors->midi_pencil;
                break;
 
-       case MouseGain:
-               mode_cursor = _cursors->cross_hair;
-               break;
-
        case MouseTimeFX:
                mode_cursor = _cursors->time_fx; // just use playhead
                break;
@@ -1127,7 +1132,7 @@ Editor::which_mode_cursor () const
        }
 
        /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
-       if (!_internal_editing && get_smart_mode() ) {
+       if (get_smart_mode()) {
 
                double x, y;
                get_pointer_position (x, y);
@@ -1163,66 +1168,40 @@ Editor::which_mode_cursor () const
 Gdk::Cursor*
 Editor::which_track_cursor () const
 {
-       Gdk::Cursor* cursor = 0;
-
-       assert (mouse_mode == MouseObject || get_smart_mode());
+       Gdk::Cursor* cursor = MouseCursors::invalid_cursor();
 
-       if (!_internal_editing) {
-               switch (_join_object_range_state) {
-               case JOIN_OBJECT_RANGE_NONE:
-               case JOIN_OBJECT_RANGE_OBJECT:
-                       cursor = which_grabber_cursor ();
-                       break;
-               case JOIN_OBJECT_RANGE_RANGE:
-                       cursor = _cursors->selector;
-                       break;
-               }
+       switch (_join_object_range_state) {
+       case JOIN_OBJECT_RANGE_NONE:
+       case JOIN_OBJECT_RANGE_OBJECT:
+               cursor = which_grabber_cursor ();
+               break;
+       case JOIN_OBJECT_RANGE_RANGE:
+               cursor = _cursors->selector;
+               break;
        }
 
        return cursor;
 }
 
-bool
-Editor::reset_canvas_cursor ()
+Gdk::Cursor*
+Editor::which_canvas_cursor(ItemType type) const
 {
-       if (!is_drawable()) {
-               return false;
-       }
-
        Gdk::Cursor* cursor = which_mode_cursor ();
 
-       if (!cursor) {
-               cursor = which_grabber_cursor ();
-       }
-               
-       if (cursor) {
-               set_canvas_cursor (cursor);
-               return true;
-       }
-
-       return false;
-}
-
-void
-Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType type)
-{
-       Gdk::Cursor* cursor = 0;
-
-       if (_drags->active()) {
-               return;
-       }
-
-       cursor = which_mode_cursor ();
-
-       if (mouse_mode == MouseObject || get_smart_mode ()) {
+       if ((mouse_mode == MouseObject || get_smart_mode ()) ||
+           mouse_mode == MouseContent) {
 
                /* find correct cursor to use in object/smart mode */
 
                switch (type) {
                case RegionItem:
-               case RegionViewNameHighlight:
-               case RegionViewName:
-               case WaveItem:
+               /* We don't choose a cursor for these items on top of a region view,
+                  because this would push a new context on the enter stack which
+                  means switching the region context for things like smart mode
+                  won't actualy change the cursor. */
+               // case RegionViewNameHighlight:
+               // case RegionViewName:
+               // case WaveItem:
                case StreamItem:
                case AutomationTrackItem:
                        cursor = which_track_cursor ();
@@ -1273,9 +1252,6 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                case FadeOutTrimHandleItem:
                        cursor = _cursors->fade_out;
                        break;
-               case NoteItem:
-                       cursor = which_grabber_cursor();
-                       break;
                case FeatureLineItem:
                        cursor = _cursors->cross_hair;
                        break;
@@ -1296,16 +1272,18 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                case CrossfadeViewItem:
                        cursor = _cursors->cross_hair;
                        break;
+               case NoteItem:
+                       cursor = _cursors->grabber_note;
                default:
                        break;
                }
 
-       } else if (mouse_mode == MouseGain) {
+       } else if (mouse_mode == MouseDraw) {
                
                /* ControlPointItem is not really specific to region gain mode
                   but it is the same cursor so don't worry about this for now.
                   The result is that we'll see the fader cursor if we enter
-                  non-region-gain-line control points while in MouseGain
+                  non-region-gain-line control points while in MouseDraw
                   mode, even though we can't edit them in this mode.
                */
 
@@ -1314,6 +1292,8 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                case ControlPointItem:
                        cursor = _cursors->fader;
                        break;
+               case NoteItem:
+                       cursor = _cursors->grabber_note;
                default:
                        break;
                }
@@ -1347,8 +1327,30 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
                break;
        }
 
-       if (cursor) {
-               set_canvas_cursor (cursor, true);
+       return cursor;
+}
+
+void
+Editor::choose_canvas_cursor_on_entry (ItemType type)
+{
+       if (_drags->active()) {
+               return;
+       }
+
+       Gdk::Cursor* cursor = which_canvas_cursor(type);
+
+       if (!_cursors->is_invalid (cursor)) {
+               // Push a new enter context
+               const EnterContext ctx = { type, CursorContext::create(*this, cursor) };
+               _enter_stack.push_back(ctx);
+       }
+}
+
+void
+Editor::update_all_enter_cursors ()
+{
+       for (std::vector<EnterContext>::iterator i = _enter_stack.begin(); i != _enter_stack.end(); ++i) {
+               i->cursor_ctx->change(which_canvas_cursor(i->item_type));
        }
 }