Fix some capitalisation in the preferences dialog.
[ardour.git] / gtk2_ardour / editor_mouse.cc
index 131d0dd6110abeb1122135b6e34beddd53f249ca..928801d0b213cda746af011ff2c70dca01ac73e4 100644 (file)
@@ -126,13 +126,13 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const
        event.button.x = x;
        event.button.y = y;
 
-       where = window_event_frame (&event, 0, 0);
+       where = window_event_sample (&event, 0, 0);
 
        return true;
 }
 
 framepos_t
-Editor::window_event_frame (GdkEvent const * event, double* pcx, double* pcy) const
+Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
 {
        double x;
        double y;
@@ -159,7 +159,7 @@ Editor::window_event_frame (GdkEvent const * event, double* pcx, double* pcy) co
 }
 
 framepos_t
-Editor::canvas_event_frame (GdkEvent const * event, double* pcx, double* pcy) const
+Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
 {
        double x;
        double y;
@@ -179,12 +179,12 @@ Editor::canvas_event_frame (GdkEvent const * event, double* pcx, double* pcy) co
                *pcy = y;
        }
 
-       /* note that pixel_to_sample() never returns less than zero, so even if the pixel
+       /* note that pixel_to_sample_from_event() never returns less than zero, so even if the pixel
           position is negative (as can be the case with motion events in particular),
           the frame location is always positive.
        */
 
-       return pixel_to_sample (x);
+       return pixel_to_sample_from_event (x);
 }
 
 Gdk::Cursor*
@@ -346,9 +346,11 @@ Editor::mouse_mode_object_range_toggled()
        assert (act);
        Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
        assert (tact);
-       if (tact->get_active())
+
+       if (tact->get_active()) {
                m = MouseObject;  //Smart mode turned to ON, force editing to Object mode
-       
+       }
+
        set_mouse_mode(m, true);  //call this so the button styles can get updated
 }
 
@@ -497,10 +499,32 @@ Editor::mouse_mode_toggled (MouseMode m)
        
        set_canvas_cursor ();
        set_gain_envelope_visibility ();
+       
+       update_time_selection_display ();
 
        MouseModeChanged (); /* EMIT SIGNAL */
 }
 
+void
+Editor::update_time_selection_display ()
+{
+       if (smart_mode_action->get_active()) {
+               /* not sure what to do here */
+               if (mouse_mode == MouseObject) {
+               } else {
+               }
+       } else {
+               switch (mouse_mode) {
+               case MouseRange:
+                       selection->clear_objects ();
+                       break;
+               default:
+                       selection->clear_time ();
+                       break;
+               }
+       }
+}
+
 void
 Editor::step_mouse_mode (bool next)
 {
@@ -599,6 +623,15 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
           to cut notes or regions.
        */
 
+       MouseMode eff_mouse_mode = mouse_mode;
+
+       if (get_smart_mode() && eff_mouse_mode == MouseRange && event->button.button == 3 && item_type == RegionItem) {
+               /* context clicks are always about object properties, even if
+                  we're in range mode within smart mode.
+               */
+               eff_mouse_mode = MouseObject;
+       }
+
        if (((mouse_mode != MouseObject) &&
             (mouse_mode != MouseAudition || item_type != RegionItem) &&
             (mouse_mode != MouseTimeFX || item_type != RegionItem) &&
@@ -627,25 +660,23 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
 
        switch (item_type) {
        case RegionItem:
-               if (!get_smart_mode() || (_join_object_range_state != JOIN_OBJECT_RANGE_RANGE)) {
-                       if (press) {
-                               if (mouse_mode != MouseRange) {
-                                       set_selected_regionview_from_click (press, op);
-                               } else {
-                                       /* don't change the selection unless the
-                                          clicked track is not currently selected. if
-                                          so, "collapse" the selection to just this
-                                          track
-                                       */
-                                       if (!selection->selected (clicked_axisview)) {
-                                               set_selected_track_as_side_effect (Selection::Set);
-                                       }
-                               }
+               if (press) {
+                       if (eff_mouse_mode != MouseRange) {
+                               set_selected_regionview_from_click (press, op);
                        } else {
-                               if (mouse_mode != MouseRange) {
-                                       set_selected_regionview_from_click (press, op);
+                               /* don't change the selection unless the
+                                  clicked track is not currently selected. if
+                                  so, "collapse" the selection to just this
+                                  track
+                               */
+                               if (!selection->selected (clicked_axisview)) {
+                                       set_selected_track_as_side_effect (Selection::Set);
                                }
                        }
+               } else {
+                       if (eff_mouse_mode != MouseRange) {
+                               set_selected_regionview_from_click (press, op);
+                       }
                }
                break;
 
@@ -653,7 +684,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
        case RegionViewName:
        case LeftFrameHandle:
        case RightFrameHandle:
-               if ( mouse_mode != MouseRange ) {
+               if (eff_mouse_mode != MouseRange) {
                        set_selected_regionview_from_click (press, op);
                } else if (event->type == GDK_BUTTON_PRESS) {
                        set_selected_track_as_side_effect (op);
@@ -666,7 +697,8 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
        case FadeOutItem:
        case StartCrossFadeItem:
        case EndCrossFadeItem:
-               if ( mouse_mode != MouseRange ) {
+               if (eff_mouse_mode != MouseRange) {
+                       cerr << "Should be setting selected regionview\n";
                        set_selected_regionview_from_click (press, op);
                } else if (event->type == GDK_BUTTON_PRESS) {
                        set_selected_track_as_side_effect (op);
@@ -675,7 +707,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
 
        case ControlPointItem:
                set_selected_track_as_side_effect (op);
-               if ( mouse_mode != MouseRange ) {
+               if (eff_mouse_mode != MouseRange) {
                        set_selected_control_point_from_click (press, op);
                }
                break;
@@ -894,17 +926,18 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        case MouseDraw:
                switch (item_type) {
                case NoteItem:
+                       /* Existing note: allow trimming/motion */
                        if (internal_editing()) {
                                /* trim notes if we're in internal edit mode and near the ends of the note */
                                NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase"));
                                assert (cn);
-                               if (cn && cn->big_enough_to_trim() && cn->mouse_near_ends()) {
+                               if (cn->big_enough_to_trim() && cn->mouse_near_ends()) {
                                        _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
                                } else {
                                        _drags->set (new NoteDrag (this, item), event);
                                }
                                return true;
-                       }
+                       } 
                        break;
                case StreamItem:
                        if (internal_editing()) {
@@ -923,10 +956,11 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        case MouseObject:
                switch (item_type) {
                case NoteItem:
+                       /* Existing note: allow trimming/motion */
                        if (internal_editing()) {
                                NoteBase* cn = reinterpret_cast<NoteBase*> (item->get_data ("notebase"));
                                assert (cn);
-                               if (cn->mouse_near_ends()) {
+                               if (cn->big_enough_to_trim() && cn->mouse_near_ends()) {
                                        _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
                                } else {
                                        _drags->set (new NoteDrag (this, item), event);
@@ -1063,7 +1097,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                                _drags->set (new RegionCreateDrag (this, item, parent), event);
                                        } else {
                                                /* See if there's a region before the click that we can extend, and extend it if so */
-                                               framepos_t const t = canvas_event_frame (event);
+                                               framepos_t const t = canvas_event_sample (event);
                                                boost::shared_ptr<Region> prev = pl->find_next_region (t, End, -1);
                                                if (!prev) {
                                                        _drags->set (new RegionCreateDrag (this, item, parent), event);
@@ -1101,7 +1135,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                                                boost::shared_ptr<Playlist> pl = t->playlist ();
                                                                if (pl) {
 
-                                                                       boost::shared_ptr<Region> r = pl->top_region_at (canvas_event_frame (event));
+                                                                       boost::shared_ptr<Region> r = pl->top_region_at (canvas_event_sample (event));
                                                                        if (r) {
                                                                                RegionView* rv = rtv->view()->find_view (r);
                                                                                clicked_selection = select_range (rv->region()->position(), 
@@ -1174,9 +1208,13 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                break;
 
        case MouseTimeFX:
-               if (internal_editing() && item_type == NoteItem) {
+               if (internal_editing() && item_type == NoteItem ) {
                        /* drag notes if we're in internal edit mode */
-                       _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+                       NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase"));
+                       assert (cn);
+                       if (cn->big_enough_to_trim()) {
+                               _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+                       }
                        return true;
                } else if (clicked_regionview) {
                        /* do time-FX  */
@@ -1268,9 +1306,9 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
        case MouseZoom:
                if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
-                       temporal_zoom_to_frame (false, canvas_event_frame (event));
+                       temporal_zoom_to_frame (false, canvas_event_sample (event));
                } else {
-                       temporal_zoom_to_frame (true, canvas_event_frame(event));
+                       temporal_zoom_to_frame (true, canvas_event_sample(event));
                }
                return true;
                break;
@@ -1311,7 +1349,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
        }
 
         pre_press_cursor = current_canvas_cursor;
-       
+
        _track_canvas->grab_focus();
 
        if (_session && _session->actively_recording()) {
@@ -1369,7 +1407,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
 
        //not rolling, range mode click + join_play_range :  locate the PH here
        if ( !_drags->active () && !_session->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && Config->get_always_play_range() ) {
-               framepos_t where = canvas_event_frame (event);
+               framepos_t where = canvas_event_sample (event);
                snap_to(where);
                _session->request_locate (where, false);
        }
@@ -1418,7 +1456,7 @@ Editor::button_release_dispatch (GdkEventButton* ev)
 bool
 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
-       framepos_t where = canvas_event_frame (event);
+       framepos_t where = canvas_event_sample (event);
        AutomationTimeAxisView* atv = 0;
 
         if (pre_press_cursor) {
@@ -1682,7 +1720,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        case AutomationTrackItem:
                                atv = dynamic_cast<AutomationTimeAxisView*>(clicked_axisview);
                                if (atv) {
-                                       atv->add_automation_event (event, where, event->button.y);
+                                       bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
+                                       atv->add_automation_event (event, where, event->button.y, with_guard_points);
                                }
                                return true;
                                break;
@@ -1701,17 +1740,20 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                */
                                AudioRegionView* arv = dynamic_cast<AudioRegionView*> (clicked_regionview);
                                if (!were_dragging && arv) {
-                                       arv->add_gain_point_event (item, event);
+                                       bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
+                                       arv->add_gain_point_event (item, event, with_guard_points);
                                }
                                return true;
                                break;
                        }
 
-                       case AutomationTrackItem:
+                       case AutomationTrackItem: {
+                               bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
                                dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->
-                                       add_automation_event (event, where, event->button.y);
+                                       add_automation_event (event, where, event->button.y, with_guard_points);
                                return true;
                                break;
+                       }
                        default:
                                break;
                        }
@@ -1861,6 +1903,17 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                }
                 break;
 
+       case RegionItem:
+               switch (effective_mouse_mode()) {
+               case MouseRange:
+                       set_canvas_cursor (_cursors->selector);
+                       break;
+               default:
+                       set_canvas_cursor (which_grabber_cursor());
+                       break;
+               }
+               break;  
+
        case StartSelectionTrimItem:
                if (is_drawable()) {
                        set_canvas_cursor (_cursors->left_side_trim);
@@ -1885,6 +1938,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                }
                break;
 
+
        case RegionViewName:
 
                /* when the name is not an active item, the entire name highlight is for trimming */
@@ -1975,7 +2029,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                line->set_outline_color (0xFF0000FF);
        }
        break;
-       
+
        case SelectionItem:
                if ( get_smart_mode() ) {
                        set_canvas_cursor ();
@@ -2860,8 +2914,6 @@ Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
                return;
        }
 
-       assert (rv);
-
        ArdourCanvas::Group* g = rv->get_canvas_group ();
        ArdourCanvas::Group* p = g->parent ();
 
@@ -2873,21 +2925,28 @@ Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
        assert (item_bbox);
        ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ());
 
-       /* Halfway across the region */
-       double const h = (parent_bbox.x0 + parent_bbox.x1) / 2;
+       /* First or last 10% of region is used for trimming, if the whole
+          region is wider than 20 pixels at the current zoom level.
+       */
 
-       Trimmable::CanTrim ct = rv->region()->can_trim ();
-       if (x <= h) {
-               if (ct & Trimmable::FrontTrimEarlier) {
-                       set_canvas_cursor (_cursors->left_side_trim);
-               } else {
-                       set_canvas_cursor (_cursors->left_side_trim_right_only);
-               }
-       } else {
-               if (ct & Trimmable::EndTrimLater) {
-                       set_canvas_cursor (_cursors->right_side_trim);
-               } else {
-                       set_canvas_cursor (_cursors->right_side_trim_left_only);
+       double const w = parent_bbox.width();
+
+       if (w > 20.0 && x >= parent_bbox.x0 && x < parent_bbox.x1) {
+               
+               Trimmable::CanTrim ct = rv->region()->can_trim ();
+
+               if (((x - parent_bbox.x0) / w) < 0.10) {
+                       if (ct & Trimmable::FrontTrimEarlier) {
+                               set_canvas_cursor (_cursors->left_side_trim, true);
+                       } else {
+                               set_canvas_cursor (_cursors->left_side_trim_right_only, true);
+                       }
+               } else if (((parent_bbox.x1 - x) / w) < 0.10) {
+                       if (ct & Trimmable::EndTrimLater) {
+                               set_canvas_cursor (_cursors->right_side_trim, true);
+                       } else {
+                               set_canvas_cursor (_cursors->right_side_trim_left_only, true);
+                       }
                }
        }
 }