diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index c3e0bd0898..24a33893db 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -1242,6 +1242,9 @@ AudioRegionView::add_ghost (TimeAxisView& tv) void AudioRegionView::entered (bool internal_editing) { + trackview.editor().set_current_trimmable (_region); + trackview.editor().set_current_movable (_region); + if (gain_line && _flags & EnvelopeVisible) { gain_line->show_all_control_points (); } @@ -1259,6 +1262,9 @@ AudioRegionView::entered (bool internal_editing) void AudioRegionView::exited () { + trackview.editor().set_current_trimmable (boost::shared_ptr()); + trackview.editor().set_current_movable (boost::shared_ptr()); + if (gain_line) { gain_line->hide_all_but_selected_control_points (); } diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc index b1bfa49ab4..a3a5dd9a1a 100644 --- a/gtk2_ardour/canvas-note-event.cc +++ b/gtk2_ardour/canvas-note-event.cc @@ -230,15 +230,18 @@ CanvasNoteEvent::set_mouse_fractions (GdkEvent* ev) { double ix, iy; double bx1, bx2, by1, by2; + bool set_cursor = false; switch (ev->type) { case GDK_MOTION_NOTIFY: ix = ev->motion.x; iy = ev->motion.y; + set_cursor = true; break; case GDK_ENTER_NOTIFY: ix = ev->crossing.x; iy = ev->crossing.y; + set_cursor = true; break; case GDK_BUTTON_PRESS: case GDK_BUTTON_RELEASE: @@ -275,7 +278,7 @@ CanvasNoteEvent::set_mouse_fractions (GdkEvent* ev) _mouse_y_fraction = yf; if (notify) { - _region.note_mouse_position (_mouse_x_fraction, _mouse_y_fraction); + _region.note_mouse_position (_mouse_x_fraction, _mouse_y_fraction, set_cursor); } } diff --git a/gtk2_ardour/canvas-note-event.h b/gtk2_ardour/canvas-note-event.h index 5267398488..191b9e2ad8 100644 --- a/gtk2_ardour/canvas-note-event.h +++ b/gtk2_ardour/canvas-note-event.h @@ -100,6 +100,9 @@ class CanvasNoteEvent : virtual public sigc::trackable virtual double x2() = 0; virtual double y2() = 0; + float mouse_x_fraction() const { return _mouse_x_fraction; } + float mouse_y_fraction() const { return _mouse_y_fraction; } + const boost::shared_ptr note() const { return _note; } MidiRegionView& region_view() const { return _region; } diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 65130dc6de..aad0f7b11a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -325,6 +325,7 @@ Editor::Editor () clicked_crossfadeview = 0; clicked_control_point = 0; last_update_frame = 0; + pre_press_cursor = 0; _drags = new DragManager (this); current_mixer_strip = 0; current_bbt_points = 0; @@ -1240,8 +1241,10 @@ Editor::build_cursors () transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0); } - - grabber_cursor = new Gdk::Cursor (HAND2); + { + Glib::RefPtr grabber_pixbuf (::get_icon ("grabber")); + grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0); + } { Glib::RefPtr grabber_note_pixbuf (::get_icon ("grabber_note")); @@ -3626,7 +3629,7 @@ Editor::clamp_verbose_cursor_y (double y) } void -Editor::show_verbose_canvas_cursor_with (const string & txt) +Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset) { verbose_canvas_cursor->property_text() = txt.c_str(); @@ -3636,6 +3639,9 @@ Editor::show_verbose_canvas_cursor_with (const string & txt) track_canvas->get_pointer (x, y); track_canvas->window_to_world (x, y, wx, wy); + wx += xoffset; + wy += yoffset; + /* don't get too close to the edge */ verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx); verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 56abdee431..f99ab00189 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -428,7 +428,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void get_regions_corresponding_to (boost::shared_ptr region, std::vector& regions); - void show_verbose_canvas_cursor_with (const std::string& txt); + void show_verbose_canvas_cursor_with (const std::string& txt, int32_t xoffset = 0, int32_t yoffset = 0); void hide_verbose_canvas_cursor(); void center_screen (framepos_t); @@ -477,7 +477,9 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD static Gdk::Cursor* transparent_cursor; Gdk::Cursor* get_canvas_cursor () const { return current_canvas_cursor; } - void set_canvas_cursor (Gdk::Cursor*); + void set_canvas_cursor (Gdk::Cursor*, bool save=false); + void set_current_trimmable (boost::shared_ptr); + void set_current_movable (boost::shared_ptr); protected: void map_transport_state (); @@ -1032,6 +1034,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD framepos_t cut_buffer_start; framecnt_t cut_buffer_length; + Gdk::Cursor* pre_press_cursor; + boost::weak_ptr _trimmable; + boost::weak_ptr _movable; + bool typed_event (ArdourCanvas::Item*, GdkEvent*, ItemType); bool button_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType); bool button_press_handler_1 (ArdourCanvas::Item *, GdkEvent *, ItemType); diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index d3a2dd6608..5a250a09b8 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -509,8 +509,8 @@ Editor::import_sndfiles (vector paths, ImportMode mode, SrcQuality quali import_status.target_regions = target_regions; import_status.track = track; import_status.replace = replace; - - track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + + set_canvas_cursor (wait_cursor); gdk_flush (); /* start import thread for this spec. this will ultimately call Session::import_audiofiles() @@ -544,7 +544,7 @@ Editor::import_sndfiles (vector paths, ImportMode mode, SrcQuality quali } - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); return 0; } @@ -560,7 +560,7 @@ Editor::embed_sndfiles (vector paths, bool multifile, int ret = 0; string path_to_use; - track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + set_canvas_cursor (wait_cursor); gdk_flush (); for (vector::iterator p = paths.begin(); p != paths.end(); ++p) { @@ -671,7 +671,7 @@ Editor::embed_sndfiles (vector paths, bool multifile, } } - track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + set_canvas_cursor (wait_cursor); for (int n = 0; n < finfo.channels; ++n) { try { @@ -712,7 +712,7 @@ Editor::embed_sndfiles (vector paths, bool multifile, ret = add_sources (paths, sources, pos, mode, target_regions, target_tracks, track, true); out: - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); return ret; } diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index faf2c7e19e..7da1464bf8 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -426,7 +426,7 @@ bool Editor::track_canvas_map_handler (GdkEventAny* /*ev*/) { if (current_canvas_cursor) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } return false; } @@ -568,7 +568,7 @@ Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert) } } - if ((autoscroll_x != last_autoscroll_x) || (autoscroll_y != last_autoscroll_y) || (autoscroll_x == 0 && autoscroll_y == 0)) { + if (autoscroll_active && ((autoscroll_x != last_autoscroll_x) || (autoscroll_y != last_autoscroll_y) || (autoscroll_x == 0 && autoscroll_y == 0))) { stop_canvas_autoscroll (); } @@ -918,12 +918,15 @@ Editor::horizontal_position () const return frame_to_unit (leftmost_frame); } void -Editor::set_canvas_cursor (Gdk::Cursor* cursor) +Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save) { - if (is_drawable()) { - track_canvas->get_window()->set_cursor(*cursor); - } + if (save) { + current_canvas_cursor = cursor; + } + if (is_drawable()) { + track_canvas->get_window()->set_cursor (*cursor); + } } bool @@ -931,7 +934,7 @@ Editor::track_canvas_key_press (GdkEventKey* event) { /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */ if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) { - track_canvas->get_window()->set_cursor (*zoom_out_cursor); + set_canvas_cursor (zoom_out_cursor); } return false; @@ -941,7 +944,7 @@ bool Editor::track_canvas_key_release (GdkEventKey* event) { if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) { - track_canvas->get_window()->set_cursor (*zoom_in_cursor); + set_canvas_cursor (zoom_in_cursor); } return false; diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index c4040c346d..33ff839ec5 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -94,7 +94,6 @@ DragManager::add (Drag* d) void DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c) { - assert (_drags.empty ()); d->set_manager (this); _drags.push_back (d); start_grab (e, c); @@ -1403,8 +1402,15 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/) { Gdk::Cursor* cursor; ArdourCanvas::CanvasNote* cnote = dynamic_cast(_item); + float x_fraction = cnote->mouse_x_fraction (); - Drag::start_grab (event); + if (x_fraction > 0.0 && x_fraction < 0.25) { + cursor = _editor->left_side_trim_cursor; + } else { + cursor = _editor->right_side_trim_cursor; + } + + Drag::start_grab (event, cursor); region = &cnote->region_view(); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 45e71e7058..95fde99826 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -198,6 +198,10 @@ Editor::which_grabber_cursor () c = grabber_edit_point_cursor; break; default: + boost::shared_ptr m = _movable.lock(); + if (m && m->locked()) { + c = speaker_cursor; + } break; } } @@ -205,6 +209,29 @@ Editor::which_grabber_cursor () return c; } +void +Editor::set_current_trimmable (boost::shared_ptr t) +{ + boost::shared_ptr st = _trimmable.lock(); + + if (!st || st == t) { + _trimmable = t; + set_canvas_cursor (); + } + +} + +void +Editor::set_current_movable (boost::shared_ptr m) +{ + boost::shared_ptr sm = _movable.lock(); + + if (!sm || sm != m) { + _movable = m; + set_canvas_cursor (); + } +} + void Editor::set_canvas_cursor () { @@ -277,9 +304,7 @@ Editor::set_canvas_cursor () } } - if (is_drawable()) { - track_canvas->get_window()->set_cursor(*current_canvas_cursor); - } + set_canvas_cursor (current_canvas_cursor, true); } void @@ -679,8 +704,9 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT if (internal_editing()) { /* trim notes if we're in internal edit mode and near the ends of the note */ ArdourCanvas::CanvasNote* cn = dynamic_cast (item); + cerr << "NoteItem button press, cursor = " << current_canvas_cursor << endl; if (cn->mouse_near_ends()) { - _drags->set (new NoteResizeDrag (this, item), event); + _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); } else { _drags->set (new NoteDrag (this, item), event); } @@ -702,12 +728,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RegionViewNameHighlight: case LeftFrameHandle: case RightFrameHandle: - { - RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id); - _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event); - return true; + if (!clicked_regionview->region()->locked()) { + RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id); + _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event); + return true; + } break; - } default: if (!internal_editing()) { @@ -723,7 +749,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT if (internal_editing()) { ArdourCanvas::CanvasNote* cn = dynamic_cast (item); if (cn->mouse_near_ends()) { - _drags->set (new NoteResizeDrag (this, item), event); + _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); } else { _drags->set (new NoteDrag (this, item), event); } @@ -802,7 +828,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RegionViewNameHighlight: case LeftFrameHandle: case RightFrameHandle: - if (!internal_editing ()) { + if (!internal_editing () && !clicked_regionview->region()->locked()) { RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id); _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event); return true; @@ -977,7 +1003,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseTimeFX: if (internal_editing() && item_type == NoteItem) { /* drag notes if we're in internal edit mode */ - _drags->set (new NoteResizeDrag (this, item), event); + _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); return true; } else if ((!internal_editing() || dynamic_cast (clicked_regionview)) && clicked_regionview) { /* do time-FX if we're not in internal edit mode, or we are but we clicked on an audio region */ @@ -992,7 +1018,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT scrub_reverse_distance = 0; last_scrub_x = event->button.x; scrubbing_direction = 0; - track_canvas->get_window()->set_cursor (*transparent_cursor); + set_canvas_cursor (transparent_cursor); return true; break; @@ -1093,6 +1119,8 @@ 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()) { @@ -1136,6 +1164,11 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT framepos_t where = event_frame (event, 0, 0); AutomationTimeAxisView* atv = 0; + if (pre_press_cursor) { + set_canvas_cursor (pre_press_cursor); + pre_press_cursor = 0; + } + /* no action if we're recording */ if (_session && _session->actively_recording()) { @@ -1411,7 +1444,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseAudition: - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); if (scrubbing_direction == 0) { /* no drag, just a click */ switch (item_type) { @@ -1505,7 +1538,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ fraction = 1.0 - (cp->get_y() / cp->line().height()); if (is_drawable() && !_drags->active ()) { - track_canvas->get_window()->set_cursor (*fader_cursor); + set_canvas_cursor (fader_cursor); } set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y); @@ -1519,7 +1552,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (line) line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get(); if (is_drawable()) { - track_canvas->get_window()->set_cursor (*fader_cursor); + set_canvas_cursor (fader_cursor); } } break; @@ -1532,26 +1565,36 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get(); } if (is_drawable()) { - track_canvas->get_window()->set_cursor (*fader_cursor); + set_canvas_cursor (fader_cursor); } } break; case RegionViewNameHighlight: if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) { - track_canvas->get_window()->set_cursor (*trimmer_cursor); + set_canvas_cursor (trimmer_cursor); } break; case LeftFrameHandle: if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) { - track_canvas->get_window()->set_cursor (*left_side_trim_cursor); + if (entered_regionview) { + Trimmable::CanTrim ct = entered_regionview->region()->can_trim(); + if ((ct & Trimmable::EndTrimEarlier) || (ct & Trimmable::EndTrimLater)) { + set_canvas_cursor (left_side_trim_cursor); + } + } } break; case RightFrameHandle: if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) { - track_canvas->get_window()->set_cursor (*right_side_trim_cursor); + if (entered_regionview) { + Trimmable::CanTrim ct = entered_regionview->region()->can_trim(); + if ((ct & Trimmable::FrontTrimEarlier) || (ct & Trimmable::FrontTrimLater)) { + set_canvas_cursor (right_side_trim_cursor); + } + } } break; @@ -1566,7 +1609,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ #endif if (is_drawable()) { - track_canvas->get_window()->set_cursor (*trimmer_cursor); + set_canvas_cursor (trimmer_cursor); } break; @@ -1574,10 +1617,10 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (is_drawable()) { switch (_edit_point) { case EditAtMouse: - track_canvas->get_window()->set_cursor (*grabber_edit_point_cursor); + set_canvas_cursor (grabber_edit_point_cursor); break; default: - track_canvas->get_window()->set_cursor (*grabber_cursor); + set_canvas_cursor (grabber_cursor); break; } } @@ -1589,7 +1632,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (mouse_mode == MouseObject && is_drawable()) { - track_canvas->get_window()->set_cursor (*trimmer_cursor); + set_canvas_cursor (trimmer_cursor); } } break; @@ -1610,7 +1653,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; } - track_canvas->get_window()->set_cursor (*cursor); + set_canvas_cursor (cursor); AutomationTimeAxisView* atv; if ((atv = static_cast(item->get_data ("trackview"))) != 0) { @@ -1627,7 +1670,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case MeterBarItem: case TempoBarItem: if (is_drawable()) { - track_canvas->get_window()->set_cursor (*timebar_cursor); + set_canvas_cursor (timebar_cursor); } break; @@ -1641,7 +1684,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case MeterMarkerItem: case TempoMarkerItem: if (is_drawable()) { - track_canvas->get_window()->set_cursor (*timebar_cursor); + set_canvas_cursor (timebar_cursor); } break; @@ -1651,7 +1694,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (rect) { rect->property_fill_color_rgba() = 0xBBBBBBAA; } - track_canvas->get_window()->set_cursor (*fade_in_cursor); + set_canvas_cursor (fade_in_cursor); } break; @@ -1661,7 +1704,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (rect) { rect->property_fill_color_rgba() = 0xBBBBBBAA; } - track_canvas->get_window()->set_cursor (*fade_out_cursor); + set_canvas_cursor (fade_out_cursor); } break; case FeatureLineItem: @@ -1724,7 +1767,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } if (is_drawable()) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } hide_verbose_canvas_cursor (); @@ -1745,7 +1788,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ #endif if (is_drawable()) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } break; @@ -1758,7 +1801,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ line->property_fill_color_rgba() = al->get_line_color(); } if (is_drawable()) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } break; @@ -1766,7 +1809,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ /* see enter_handler() for notes */ if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (is_drawable() && mouse_mode == MouseObject) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } } break; @@ -1778,7 +1821,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case TempoBarItem: case MarkerBarItem: if (is_drawable()) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } break; @@ -1795,7 +1838,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case TempoMarkerItem: if (is_drawable()) { - track_canvas->get_window()->set_cursor (*timebar_cursor); + set_canvas_cursor (timebar_cursor); } break; @@ -1810,12 +1853,12 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ rect->property_outline_pixels() = 0; } } - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); break; case AutomationTrackItem: if (is_drawable()) { - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); clear_entered_track = true; Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track)); } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index abd319583b..751c94fefa 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -3708,14 +3708,14 @@ Editor::freeze_route () pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this); - track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + set_canvas_cursor (wait_cursor); while (!itt.done && !itt.cancel) { gtk_main_iteration (); } current_interthread_info = 0; - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } void @@ -4585,7 +4585,7 @@ Editor::normalize_region () begin_reversible_command (_("normalize")); - track_canvas->get_window()->set_cursor (*wait_cursor); + set_canvas_cursor (wait_cursor); gdk_flush (); double maxamp = 0; @@ -4613,7 +4613,7 @@ Editor::normalize_region () } commit_reversible_command (); - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); _last_normalization_value = spin.get_value (); } @@ -4804,7 +4804,7 @@ Editor::fork_region () begin_reversible_command (_("Fork Region(s)")); - track_canvas->get_window()->set_cursor (*wait_cursor); + set_canvas_cursor (wait_cursor); gdk_flush (); for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) { @@ -4828,7 +4828,7 @@ Editor::fork_region () commit_reversible_command (); rs.clear (); - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } void @@ -4867,7 +4867,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress begin_reversible_command (command); - track_canvas->get_window()->set_cursor (*wait_cursor); + set_canvas_cursor (wait_cursor); gdk_flush (); int n = 0; @@ -4929,7 +4929,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress rs.clear (); out: - track_canvas->get_window()->set_cursor (*current_canvas_cursor); + set_canvas_cursor (current_canvas_cursor); } void diff --git a/gtk2_ardour/icons/grabber.png b/gtk2_ardour/icons/grabber.png new file mode 100644 index 0000000000..4a449e752d Binary files /dev/null and b/gtk2_ardour/icons/grabber.png differ diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 94083bf73d..136515c08e 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -99,6 +99,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView & , _optimization_iterator (_events.end()) , _list_editor (0) , no_sound_notes (false) + , pre_enter_cursor (0) { _note_group->raise_to_top(); PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys)); @@ -2222,7 +2223,7 @@ MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron len = 0; } } else { - if (beats >= canvas_note->note()->end_time()) { + if (beats >= canvas_note->note()->time()) { len = beats - canvas_note->note()->time(); } else { len = 0; @@ -2479,7 +2480,7 @@ MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush) char buf[24]; snprintf (buf, sizeof (buf), "Vel %d", (int) (*_selection.begin())->note()->velocity()); - trackview.editor().show_verbose_canvas_cursor_with (buf); + trackview.editor().show_verbose_canvas_cursor_with (buf, 10, 10); } } @@ -2668,11 +2669,15 @@ MidiRegionView::note_left (ArdourCanvas::CanvasNoteEvent* note) } editor->hide_verbose_canvas_cursor (); - editor->set_canvas_cursor (pre_enter_cursor); + + if (pre_enter_cursor) { + editor->set_canvas_cursor (pre_enter_cursor); + pre_enter_cursor = 0; + } } void -MidiRegionView::note_mouse_position (float x_fraction, float y_fraction) +MidiRegionView::note_mouse_position (float x_fraction, float y_fraction, bool can_set_cursor) { Editor* editor = dynamic_cast(&trackview.editor()); @@ -2681,7 +2686,9 @@ MidiRegionView::note_mouse_position (float x_fraction, float y_fraction) } else if (x_fraction >= 0.75 && x_fraction < 1.0) { editor->set_canvas_cursor (editor->right_side_trim_cursor); } else { - editor->set_canvas_cursor (pre_enter_cursor); + if (pre_enter_cursor && can_set_cursor) { + editor->set_canvas_cursor (pre_enter_cursor); + } } } @@ -3001,7 +3008,7 @@ MidiRegionView::show_verbose_canvas_cursor (boost::shared_ptr n) const Evoral::midi_note_name (n->note()).c_str(), (int) n->note (), (int) n->velocity()); - trackview.editor().show_verbose_canvas_cursor_with (buf); + trackview.editor().show_verbose_canvas_cursor_with (buf, 10, 20); } void diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index b2b54c5f3c..29ad2f7821 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -190,11 +190,9 @@ class MidiRegionView : public RegionView void apply_diff_as_subcommand(); void abort_command(); - Gdk::Cursor* pre_enter_cursor; - void note_entered(ArdourCanvas::CanvasNoteEvent* ev); void note_left(ArdourCanvas::CanvasNoteEvent* ev); - void note_mouse_position (float xfraction, float yfraction); + void note_mouse_position (float xfraction, float yfraction, bool can_set_cursor=true); void unique_select(ArdourCanvas::CanvasNoteEvent* ev); void note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend=false); void note_deselected(ArdourCanvas::CanvasNoteEvent* ev); @@ -434,6 +432,8 @@ class MidiRegionView : public RegionView void get_events (Events& e, Evoral::Sequence::NoteOperator op, uint8_t val, int chan_mask = 0); void display_program_changes_on_channel (uint8_t); + + Gdk::Cursor* pre_enter_cursor; }; diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 9c7750adca..e19ba14836 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -45,6 +45,8 @@ namespace ARDOUR { class Region; class Playlist; class RouteGroup; + class Trimmable; + class Movable; } namespace Gtk { @@ -353,9 +355,12 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible { virtual TimeAxisView* axis_view_from_route (boost::shared_ptr) const = 0; - virtual void show_verbose_canvas_cursor_with (const std::string& txt) = 0; + virtual void show_verbose_canvas_cursor_with (const std::string& txt, int32_t xoffset = 0, int32_t yoffset = 0) = 0; virtual void hide_verbose_canvas_cursor() = 0; + virtual void set_current_trimmable (boost::shared_ptr) = 0; + virtual void set_current_movable (boost::shared_ptr) = 0; + virtual void center_screen (framepos_t) = 0; virtual TrackViewList axis_views_from_routes (boost::shared_ptr) const = 0; diff --git a/libs/ardour/ardour/movable.h b/libs/ardour/ardour/movable.h new file mode 100644 index 0000000000..26b6125888 --- /dev/null +++ b/libs/ardour/ardour/movable.h @@ -0,0 +1,15 @@ +#ifndef __libardour_movable_h__ +#define __libardour_movable_h__ + +namespace ARDOUR { + +class Movable { + public: + Movable() {} + + bool locked () const { return false; } +}; + +} + +#endif /* __libardour_movable_h__ */ diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 0ae325d124..ef86dce4b2 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -31,8 +31,10 @@ #include "ardour/ardour.h" #include "ardour/data_type.h" #include "ardour/automatable.h" +#include "ardour/movable.h" #include "ardour/readable.h" #include "ardour/session_object.h" +#include "ardour/trimmable.h" class XMLNode; @@ -81,6 +83,8 @@ class Region : public SessionObject , public boost::enable_shared_from_this , public Readable + , public Trimmable + , public Movable { public: typedef std::vector > SourceList; @@ -147,6 +151,8 @@ class Region bool sync_marked() const { return _sync_marked; } bool external() const { return _external; } bool import() const { return _import; } + + Trimmable::CanTrim can_trim() const; PositionLockStyle position_lock_style() const { return _position_lock_style; } void set_position_lock_style (PositionLockStyle ps); diff --git a/libs/ardour/ardour/trimmable.h b/libs/ardour/ardour/trimmable.h new file mode 100644 index 0000000000..e053a2deed --- /dev/null +++ b/libs/ardour/ardour/trimmable.h @@ -0,0 +1,36 @@ +#ifndef __libardour_trimmable_h__ +#define __libardour_trimmable_h__ + +namespace ARDOUR { + +class Trimmable { + public: + Trimmable() {} + virtual ~Trimmable() {} + + enum CanTrim { + FrontTrimEarlier, + FrontTrimLater, + EndTrimEarlier, + EndTrimLater, + TopTrimUp, + TopTrimDown, + BottomTrimUp, + BottomTrimDown + } ; + + virtual CanTrim can_trim() const { + return CanTrim (FrontTrimEarlier | + FrontTrimLater | + EndTrimEarlier | + EndTrimLater | + TopTrimUp | + TopTrimDown | + BottomTrimUp | + BottomTrimDown); + } +}; + +} + +#endif /* __libardour_trimmable_h__ */ diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 7e78475eb3..6d4be37b6d 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1587,3 +1587,31 @@ Region::use_sources (SourceList const & s) } } } + +Trimmable::CanTrim +Region::can_trim () const +{ + CanTrim ct = CanTrim (0); + + if (locked()) { + return ct; + } + + /* if not locked, we can always move the front later, and the end earlier + */ + + ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier); + + if (start() != 0) { + ct = CanTrim (ct | FrontTrimEarlier); + } + + if (!_sources.empty()) { + if (last_frame() < _sources.front()->length (0)) { + ct = CanTrim (ct | EndTrimLater); + } + } + + return ct; +} + diff --git a/libs/pbd/enumwriter.cc b/libs/pbd/enumwriter.cc index 2c6e5c73c8..5263a886fb 100644 --- a/libs/pbd/enumwriter.cc +++ b/libs/pbd/enumwriter.cc @@ -181,6 +181,41 @@ EnumWriter::write_distinct (EnumRegistration& er, int value) return string(); } +int +EnumWriter::validate (EnumRegistration& er, int val) +{ + if (er.values.empty()) { + return val; + } + + if (val == 0) { + /* zero is always a legal value for our enumerations, just about + */ + return val; + } + + vector::iterator i; + string enum_name = _("unknown enumeration"); + + for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) { + if (&er == &(*x).second) { + enum_name = (*x).first; + } + } + + + for (i = er.values.begin(); i != er.values.end(); ++i) { + if (*i == val) { + return val; + } + } + + warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"), + enum_name, val, er.names.front()) + << endmsg; + return er.values.front(); +} + int EnumWriter::read_bits (EnumRegistration& er, string str) { @@ -193,14 +228,16 @@ EnumWriter::read_bits (EnumRegistration& er, string str) /* catch old-style hex numerics */ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') { - return strtol (str.c_str(), (char **) 0, 16); + int val = strtol (str.c_str(), (char **) 0, 16); + return validate (er, val); } /* catch old style dec numerics */ if (strspn (str.c_str(), "0123456789") == str.length()) { - return strtol (str.c_str(), (char **) 0, 10); - } + int val = strtol (str.c_str(), (char **) 0, 10); + return validate (er, val); + } do { @@ -238,14 +275,16 @@ EnumWriter::read_distinct (EnumRegistration& er, string str) /* catch old-style hex numerics */ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') { - return strtol (str.c_str(), (char **) 0, 16); + int val = strtol (str.c_str(), (char **) 0, 16); + return validate (er, val); } /* catch old style dec numerics */ if (strspn (str.c_str(), "0123456789") == str.length()) { - return strtol (str.c_str(), (char **) 0, 10); - } + int val = strtol (str.c_str(), (char **) 0, 10); + return validate (er, val); + } for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) { if (str == (*s) || nocase_cmp (str, *s) == 0) { diff --git a/libs/pbd/pbd/enumwriter.h b/libs/pbd/pbd/enumwriter.h index 461665d739..a253719c85 100644 --- a/libs/pbd/pbd/enumwriter.h +++ b/libs/pbd/pbd/enumwriter.h @@ -71,6 +71,9 @@ class EnumWriter { static EnumWriter* _instance; static std::map hack_table; + + + int validate (EnumRegistration& er, int value); }; }