X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=c91337bb6e8dee1657a569b4723e2ceed8a8a36e;hb=5fef65538040fbac1b9edd1847a269aa925a49c9;hp=286c3a8fb8c9f99b74835c19f8599b9409818426;hpb=4c79d358387c172683467e7e53e7c78a65a7f4d0;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 286c3a8fb8..c91337bb6e 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -142,9 +142,9 @@ const double Editor::timebar_height = 15.0; static const gchar *_snap_type_strings[] = { N_("CD Frames"), - N_("Timecode Frames"), - N_("Timecode Seconds"), - N_("Timecode Minutes"), + N_("TC Frames"), + N_("TC Seconds"), + N_("TC Minutes"), N_("Seconds"), N_("Minutes"), N_("Beats/128"), @@ -188,6 +188,14 @@ static const gchar *_edit_point_strings[] = { 0 }; +static const gchar *_edit_mode_strings[] = { + N_("Slide"), + N_("Splice"), + N_("Ripple"), + N_("Lock"), + 0 +}; + static const gchar *_zoom_focus_strings[] = { N_("Left"), N_("Right"), @@ -211,6 +219,8 @@ static const gchar *_rb_opt_strings[] = { }; #endif +#define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5) + static void pane_size_watcher (Paned* pane) { @@ -295,6 +305,8 @@ Editor::Editor () selection = new Selection (this); cut_buffer = new Selection (this); + _selection_memento = new SelectionMemento (); + before.clear(); clicked_regionview = 0; clicked_axisview = 0; @@ -302,6 +314,8 @@ Editor::Editor () clicked_control_point = 0; last_update_frame = 0; pre_press_cursor = 0; + last_paste_pos = 0; + paste_count = 0; _drags = new DragManager (this); lock_dialog = 0; ruler_dialog = 0; @@ -311,6 +325,7 @@ Editor::Editor () snap_type_strings = I18N (_snap_type_strings); snap_mode_strings = I18N (_snap_mode_strings); zoom_focus_strings = I18N (_zoom_focus_strings); + edit_mode_strings = I18N (_edit_mode_strings); edit_point_strings = I18N (_edit_point_strings); #ifdef USE_RUBBERBAND rb_opt_strings = I18N (_rb_opt_strings); @@ -377,17 +392,16 @@ Editor::Editor () sfbrowser = 0; - location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker(); - location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange(); - location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker(); - location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop(); - location_punch_color = ARDOUR_UI::config()->get_canvasvar_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"); zoom_focus = ZoomFocusLeft; _edit_point = EditAtMouse; - _internal_editing = false; current_canvas_cursor = 0; - _visible_track_count = 16; + _visible_track_count = -1; samples_per_pixel = 2048; /* too early to use reset_zoom () */ @@ -473,6 +487,8 @@ Editor::Editor () initialize_canvas (); + CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus)); + _summary = new EditorSummary (this); selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed)); @@ -540,6 +556,12 @@ Editor::Editor () _snapshots = new EditorSnapshots (this); _locations = new EditorLocations (this); + /* these are static location signals */ + + Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context()); + Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context()); + Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context()); + add_notebook_page (_("Regions"), _regions->widget ()); add_notebook_page (_("Tracks & Busses"), _routes->widget ()); add_notebook_page (_("Snapshots"), _snapshots->widget ()); @@ -647,11 +669,6 @@ Editor::Editor () _snap_mode = SnapOff; set_snap_mode (_snap_mode); set_mouse_mode (MouseObject, true); - pre_internal_mouse_mode = MouseObject; - pre_internal_snap_type = _snap_type; - pre_internal_snap_mode = _snap_mode; - internal_snap_type = _snap_type; - internal_snap_mode = _snap_mode; set_edit_point_preference (EditAtMouse, true); _playlist_selector = new PlaylistSelector(); @@ -662,11 +679,9 @@ Editor::Editor () /* nudge stuff */ nudge_forward_button.set_name ("nudge button"); -// nudge_forward_button.add_elements (ArdourButton::Inset); nudge_forward_button.set_image(::get_icon("nudge_right")); nudge_backward_button.set_name ("nudge button"); -// nudge_backward_button.add_elements (ArdourButton::Inset); nudge_backward_button.set_image(::get_icon("nudge_left")); fade_context_menu.set_name ("ArdourContextMenu"); @@ -744,6 +759,8 @@ Editor::Editor () _last_region_menu_was_main = false; _popup_region_menu_item = 0; + _ignore_follow_edits = false; + _show_marker_lines = false; /* Button bindings */ @@ -775,6 +792,7 @@ Editor::~Editor() delete _route_groups; delete _track_canvas_viewport; delete _drags; + delete nudge_clock; } XMLNode* @@ -791,12 +809,24 @@ Editor::button_settings () const } void -Editor::add_toplevel_controls (Container& cont) +Editor::add_toplevel_menu (Container& cont) { vpacker.pack_start (cont, false, false); cont.show_all (); } +void +Editor::add_transport_frame (Container& cont) +{ + if(ARDOUR::Profile->get_mixbus()) { + global_vpacker.pack_start (cont, false, false); + global_vpacker.reorder_child (cont, 0); + cont.show_all (); + } else { + vpacker.pack_start (cont, false, false); + } +} + bool Editor::get_smart_mode () const { @@ -841,7 +871,7 @@ Editor::set_entered_regionview (RegionView* rv) entered_regionview = rv; if (entered_regionview != 0) { - entered_regionview->entered (internal_editing ()); + entered_regionview->entered (); } if (!_all_region_actions_sensitized && _last_region_menu_was_main) { @@ -870,6 +900,7 @@ void Editor::show_window () { if (!is_visible ()) { + DisplaySuspender ds; show_all (); /* XXX: this is a bit unfortunate; it would probably @@ -896,7 +927,7 @@ Editor::show_window () if (current_mixer_strip) { current_mixer_strip->hide_things (); - current_mixer_strip->parameter_changed ("mixer-strip-visibility"); + current_mixer_strip->parameter_changed ("mixer-element-visibility"); } } @@ -1030,12 +1061,12 @@ Editor::control_scroll (float fraction) _dragging_playhead = true; } - if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) { + if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) { *_control_scroll_target = 0; } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) { *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen } else { - *_control_scroll_target += (framepos_t) floor (step); + *_control_scroll_target += (framepos_t) trunc (step); } /* move visuals, we'll catch up with it later */ @@ -1124,9 +1155,28 @@ Editor::generic_event_handler (GdkEvent* ev) case GDK_KEY_RELEASE: gettimeofday (&last_event_time, 0); break; + + case GDK_LEAVE_NOTIFY: + switch (ev->crossing.detail) { + case GDK_NOTIFY_UNKNOWN: + case GDK_NOTIFY_INFERIOR: + case GDK_NOTIFY_ANCESTOR: + break; + case GDK_NOTIFY_VIRTUAL: + case GDK_NOTIFY_NONLINEAR: + case GDK_NOTIFY_NONLINEAR_VIRTUAL: + /* leaving window, so reset focus, thus ending any and + all text entry operations. + */ + reset_focus(); + break; + } + break; + default: break; } + return false; } @@ -1139,7 +1189,7 @@ Editor::lock_timeout_callback () timersub (&now, &last_event_time, &delta); - if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) { + if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) { lock (); /* don't call again. Returning false will effectively disconnect us from the timer callback. @@ -1304,7 +1354,6 @@ Editor::set_session (Session *t) _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context()); _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context()); _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context()); - _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context()); _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context()); playhead_cursor->show (); @@ -1339,6 +1388,7 @@ Editor::set_session (Session *t) /* register for undo history */ _session->register_with_memento_command_factory(id(), this); + _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento); ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated)); @@ -1431,8 +1481,10 @@ void Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/) { using namespace Menu_Helpers; - AudioRegionView* arv = static_cast (item->get_data ("regionview")); - assert(arv); + AudioRegionView* arv = dynamic_cast ((RegionView*)item->get_data ("regionview")); + if (!arv) { + return; + } MenuList& items (xfade_in_context_menu.items()); items.clear (); @@ -1454,8 +1506,10 @@ void Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/) { using namespace Menu_Helpers; - AudioRegionView* arv = static_cast (item->get_data ("regionview")); - assert(arv); + AudioRegionView* arv = dynamic_cast ((RegionView*)item->get_data ("regionview")); + if (!arv) { + return; + } MenuList& items (xfade_out_context_menu.items()); items.clear (); @@ -1746,6 +1800,9 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection))); edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true))); + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false))); + edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection))); @@ -1789,6 +1846,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false))); edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection))); + edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection))); edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection))); @@ -1836,7 +1894,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) select_menu->set_name ("ArdourContextMenu"); select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); - select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set))); select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track))); select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); @@ -1913,7 +1971,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) select_menu->set_name ("ArdourContextMenu"); select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); - select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set))); select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track))); select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); @@ -2028,12 +2086,6 @@ Editor::set_snap_mode (SnapMode mode) { string str = snap_mode_strings[(int)mode]; - if (_internal_editing) { - internal_snap_mode = mode; - } else { - pre_internal_snap_mode = mode; - } - _snap_mode = mode; if (str != snap_mode_selector.get_text ()) { @@ -2048,8 +2100,11 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) bool changed = (_edit_point != ep); _edit_point = ep; - string str = edit_point_strings[(int)ep]; + if (Profile->get_mixbus()) + if (ep == EditAtSelectedMarker) + ep = EditAtPlayhead; + string str = edit_point_strings[(int)ep]; if (str != edit_point_selector.get_text ()) { edit_point_selector.set_text (str); } @@ -2144,7 +2199,12 @@ Editor::set_state (const XMLNode& node, int /*version*/) if (_session && (prop = node.property ("playhead"))) { framepos_t pos; sscanf (prop->value().c_str(), "%" PRIi64, &pos); - playhead_cursor->set_position (pos); + if (pos >= 0) { + playhead_cursor->set_position (pos); + } else { + warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg; + playhead_cursor->set_position (0); + } } else { playhead_cursor->set_position (0); } @@ -2177,23 +2237,6 @@ Editor::set_state (const XMLNode& node, int /*version*/) snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode)); } - if ((prop = node.property ("internal-snap-to"))) { - internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type); - } - - if ((prop = node.property ("internal-snap-mode"))) { - internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode); - } - - if ((prop = node.property ("pre-internal-snap-to"))) { - pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type); - } - - - if ((prop = node.property ("pre-internal-snap-mode"))) { - pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode); - } - if ((prop = node.property ("mouse-mode"))) { MouseMode m = str2mousemode(prop->value()); set_mouse_mode (m, true); @@ -2215,16 +2258,6 @@ Editor::set_state (const XMLNode& node, int /*version*/) reset_y_origin (atof (prop->value ())); } - if ((prop = node.property ("internal-edit"))) { - bool yn = string_is_affirmative (prop->value()); - RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit")); - if (act) { - RefPtr tact = RefPtr::cast_dynamic(act); - tact->set_active (!yn); - tact->set_active (yn); - } - } - if ((prop = node.property ("join-object-range"))) { RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range")); bool yn = string_is_affirmative (prop->value()); @@ -2395,10 +2428,6 @@ Editor::get_state () node->add_property ("zoom", buf); node->add_property ("snap-to", enum_2_string (_snap_type)); node->add_property ("snap-mode", enum_2_string (_snap_mode)); - node->add_property ("internal-snap-to", enum_2_string (internal_snap_type)); - node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode)); - node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type)); - node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode)); node->add_property ("edit-point", enum_2_string (_edit_point)); snprintf (buf, sizeof(buf), "%d", _visible_track_count); node->add_property ("visible-track-count", buf); @@ -2416,7 +2445,6 @@ Editor::get_state () node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no"); node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ())); node->add_property ("mouse-mode", enum2str(mouse_mode)); - node->add_property ("internal-edit", _internal_editing ? "yes" : "no"); node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no"); Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); @@ -2488,7 +2516,7 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const * @param event Event to get current key modifier information from, or 0. */ void -Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark) +Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark) { if (!_session || !event) { return; @@ -2506,7 +2534,7 @@ Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_ } void -Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark) +Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark) { if (!_session || _snap_mode == SnapOff) { return; @@ -2516,14 +2544,17 @@ Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark) } void -Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/) +Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/) { const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame()); framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60); switch (_snap_type) { case SnapToTimecodeFrame: - if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) { + /* start is already on a whole timecode frame, do nothing */ + } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) { start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame()); } else { start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame()); @@ -2536,7 +2567,10 @@ Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /* } else { start -= _session->config.get_timecode_offset (); } - if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + (start % one_timecode_second == 0)) { + /* start is already on a whole second, do nothing */ + } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) { start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second; } else { start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second; @@ -2555,7 +2589,10 @@ Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /* } else { start -= _session->config.get_timecode_offset (); } - if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + (start % one_timecode_minute == 0)) { + /* start is already on a whole minute, do nothing */ + } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) { start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute; } else { start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute; @@ -2568,12 +2605,12 @@ Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /* break; default: fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } } void -Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) +Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark) { const framepos_t one_second = _session->frame_rate(); const framepos_t one_minute = _session->frame_rate() * 60; @@ -2588,7 +2625,10 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) return timecode_snap_to_internal (start, direction, for_mark); case SnapToCDFrame: - if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + start % (one_second/75) == 0) { + /* start is already on a whole CD frame, do nothing */ + } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) { start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75); } else { start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75); @@ -2596,7 +2636,10 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) break; case SnapToSeconds: - if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + start % one_second == 0) { + /* start is already on a whole second, do nothing */ + } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) { start = (framepos_t) ceil ((double) start / one_second) * one_second; } else { start = (framepos_t) floor ((double) start / one_second) * one_second; @@ -2604,7 +2647,10 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) break; case SnapToMinutes: - if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) { + if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && + start % one_minute == 0) { + /* start is already on a whole minute, do nothing */ + } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) { start = (framepos_t) ceil ((double) start / one_minute) * one_minute; } else { start = (framepos_t) floor ((double) start / one_minute) * one_minute; @@ -2758,26 +2804,42 @@ Editor::setup_toolbar () { HBox* mode_box = manage(new HBox); mode_box->set_border_width (2); - mode_box->set_spacing(4); + mode_box->set_spacing(2); HBox* mouse_mode_box = manage (new HBox); HBox* mouse_mode_hbox = manage (new HBox); VBox* mouse_mode_vbox = manage (new VBox); Alignment* mouse_mode_align = manage (new Alignment); - Glib::RefPtr mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH); -// mouse_mode_size_group->add_widget (smart_mode_button); + Glib::RefPtr mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL); + mouse_mode_size_group->add_widget (smart_mode_button); mouse_mode_size_group->add_widget (mouse_move_button); + mouse_mode_size_group->add_widget (mouse_cut_button); mouse_mode_size_group->add_widget (mouse_select_button); - mouse_mode_size_group->add_widget (mouse_zoom_button); - mouse_mode_size_group->add_widget (mouse_gain_button); mouse_mode_size_group->add_widget (mouse_timefx_button); mouse_mode_size_group->add_widget (mouse_audition_button); mouse_mode_size_group->add_widget (mouse_draw_button); - mouse_mode_size_group->add_widget (internal_edit_button); + mouse_mode_size_group->add_widget (mouse_content_button); + + mouse_mode_size_group->add_widget (zoom_in_button); + mouse_mode_size_group->add_widget (zoom_out_button); + mouse_mode_size_group->add_widget (zoom_preset_selector); + mouse_mode_size_group->add_widget (zoom_out_full_button); + mouse_mode_size_group->add_widget (zoom_focus_selector); - /* make them just a bit bigger */ - mouse_move_button.set_size_request (-1, 30); + mouse_mode_size_group->add_widget (tav_shrink_button); + mouse_mode_size_group->add_widget (tav_expand_button); + mouse_mode_size_group->add_widget (visible_tracks_selector); + + mouse_mode_size_group->add_widget (snap_type_selector); + mouse_mode_size_group->add_widget (snap_mode_selector); + + mouse_mode_size_group->add_widget (edit_point_selector); + mouse_mode_size_group->add_widget (edit_mode_selector); + + mouse_mode_size_group->add_widget (*nudge_clock); + mouse_mode_size_group->add_widget (nudge_forward_button); + mouse_mode_size_group->add_widget (nudge_backward_button); mouse_mode_hbox->set_spacing (2); @@ -2787,14 +2849,16 @@ Editor::setup_toolbar () mouse_mode_hbox->pack_start (mouse_move_button, false, false); mouse_mode_hbox->pack_start (mouse_select_button, false, false); - mouse_mode_hbox->pack_start (mouse_zoom_button, false, false); + if (!ARDOUR::Profile->get_mixbus()) { + mouse_mode_hbox->pack_start (mouse_cut_button, false, false); + } + if (!ARDOUR::Profile->get_trx()) { - mouse_mode_hbox->pack_start (mouse_gain_button, false, false); mouse_mode_hbox->pack_start (mouse_timefx_button, false, false); mouse_mode_hbox->pack_start (mouse_audition_button, false, false); mouse_mode_hbox->pack_start (mouse_draw_button, false, false); - mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8); + mouse_mode_hbox->pack_start (mouse_content_button, false, false); } mouse_mode_vbox->pack_start (*mouse_mode_hbox); @@ -2805,8 +2869,6 @@ Editor::setup_toolbar () mouse_mode_box->pack_start (*mouse_mode_align, false, false); edit_mode_selector.set_name ("mouse mode button"); - edit_mode_selector.set_size_request (65, -1); - edit_mode_selector.add_elements (ArdourButton::Inset); if (!ARDOUR::Profile->get_trx()) { mode_box->pack_start (edit_mode_selector, false, false); @@ -2817,7 +2879,7 @@ Editor::setup_toolbar () _mouse_mode_tearoff->set_name ("MouseModeBase"); _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false); - if (Profile->get_sae()) { + if (Profile->get_sae() || Profile->get_mixbus() ) { _mouse_mode_tearoff->set_can_be_torn_off (false); } @@ -2837,67 +2899,68 @@ Editor::setup_toolbar () RefPtr act; + zoom_preset_selector.set_name ("zoom button"); + zoom_preset_selector.set_image(::get_icon ("time_exp")); + zoom_preset_selector.set_size_request (42, -1); + zoom_in_button.set_name ("zoom button"); -// zoom_in_button.add_elements ( ArdourButton::Inset ); - zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_in_button.set_image(::get_icon ("zoom_in")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in")); zoom_in_button.set_related_action (act); zoom_out_button.set_name ("zoom button"); -// zoom_out_button.add_elements ( ArdourButton::Inset ); - zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_out_button.set_image(::get_icon ("zoom_out")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out")); zoom_out_button.set_related_action (act); zoom_out_full_button.set_name ("zoom button"); -// zoom_out_full_button.add_elements ( ArdourButton::Inset ); - zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_out_full_button.set_image(::get_icon ("zoom_full")); act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session")); zoom_out_full_button.set_related_action (act); zoom_focus_selector.set_name ("zoom button"); - zoom_focus_selector.set_size_request (80, -1); -// zoom_focus_selector.add_elements (ArdourButton::Inset); - if (!ARDOUR::Profile->get_trx()) { + if (ARDOUR::Profile->get_mixbus()) { + _zoom_box.pack_start (zoom_preset_selector, false, false); + } else if (ARDOUR::Profile->get_trx()) { + mode_box->pack_start (zoom_out_button, false, false); + mode_box->pack_start (zoom_in_button, false, false); + } else { _zoom_box.pack_start (zoom_out_button, false, false); _zoom_box.pack_start (zoom_in_button, false, false); _zoom_box.pack_start (zoom_out_full_button, false, false); _zoom_box.pack_start (zoom_focus_selector, false, false); - } else { - mode_box->pack_start (zoom_out_button, false, false); - mode_box->pack_start (zoom_in_button, false, false); } /* Track zoom buttons */ visible_tracks_selector.set_name ("zoom button"); -// visible_tracks_selector.add_elements ( ArdourButton::Inset ); - set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2); + if (Profile->get_mixbus()) { + visible_tracks_selector.set_image(::get_icon ("tav_exp")); + visible_tracks_selector.set_size_request (42, -1); + } else { + set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2); + } tav_expand_button.set_name ("zoom button"); -// tav_expand_button.add_elements ( ArdourButton::FlatFace ); - tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); - tav_expand_button.set_size_request (-1, 20); tav_expand_button.set_image(::get_icon ("tav_exp")); act = ActionManager::get_action (X_("Editor"), X_("expand-tracks")); tav_expand_button.set_related_action (act); tav_shrink_button.set_name ("zoom button"); -// tav_shrink_button.add_elements ( ArdourButton::FlatFace ); - tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); - tav_shrink_button.set_size_request (-1, 20); tav_shrink_button.set_image(::get_icon ("tav_shrink")); act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks")); tav_shrink_button.set_related_action (act); - if (!ARDOUR::Profile->get_trx()) { + if (ARDOUR::Profile->get_mixbus()) { _zoom_box.pack_start (visible_tracks_selector); + } else if (ARDOUR::Profile->get_trx()) { + _zoom_box.pack_start (tav_shrink_button); + _zoom_box.pack_start (tav_expand_button); + } else { + _zoom_box.pack_start (visible_tracks_selector); + _zoom_box.pack_start (tav_shrink_button); + _zoom_box.pack_start (tav_expand_button); } - _zoom_box.pack_start (tav_shrink_button); - _zoom_box.pack_start (tav_expand_button); if (!ARDOUR::Profile->get_trx()) { _zoom_tearoff = manage (new TearOff (_zoom_box)); @@ -2912,20 +2975,18 @@ Editor::setup_toolbar () &_zoom_tearoff->tearoff_window(), 0)); } + if (Profile->get_sae() || Profile->get_mixbus() ) { + _zoom_tearoff->set_can_be_torn_off (false); + } + snap_box.set_spacing (2); snap_box.set_border_width (2); snap_type_selector.set_name ("mouse mode button"); - snap_type_selector.set_size_request (140, -1); - snap_type_selector.add_elements (ArdourButton::Inset); snap_mode_selector.set_name ("mouse mode button"); - snap_mode_selector.set_size_request (85, -1); - snap_mode_selector.add_elements (ArdourButton::Inset); edit_point_selector.set_name ("mouse mode button"); - edit_point_selector.set_size_request (85, -1); - edit_point_selector.add_elements (ArdourButton::Inset); snap_box.pack_start (snap_mode_selector, false, false); snap_box.pack_start (snap_type_selector, false, false); @@ -2940,9 +3001,6 @@ Editor::setup_toolbar () nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false); nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false); - nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); - nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); - nudge_box->pack_start (nudge_backward_button, false, false); nudge_box->pack_start (nudge_forward_button, false, false); nudge_box->pack_start (*nudge_clock, false, false); @@ -2951,13 +3009,13 @@ Editor::setup_toolbar () /* Pack everything in... */ HBox* hbox = manage (new HBox); - hbox->set_spacing(10); + hbox->set_spacing(2); _tools_tearoff = manage (new TearOff (*hbox)); _tools_tearoff->set_name ("MouseModeBase"); _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false); - if (Profile->get_sae()) { + if (Profile->get_sae() || Profile->get_mixbus()) { _tools_tearoff->set_can_be_torn_off (false); } @@ -2970,7 +3028,7 @@ Editor::setup_toolbar () _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &_tools_tearoff->tearoff_window(), 0)); - toolbar_hbox.set_spacing (10); + toolbar_hbox.set_spacing (2); toolbar_hbox.set_border_width (1); toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false); @@ -2981,7 +3039,7 @@ Editor::setup_toolbar () if (!ARDOUR::Profile->get_trx()) { hbox->pack_start (snap_box, false, false); - if (!Profile->get_small_screen()) { + if ( !Profile->get_small_screen() || Profile->get_mixbus() ) { hbox->pack_start (*nudge_box, false, false); } else { ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false); @@ -3009,19 +3067,24 @@ Editor::build_edit_point_menu () using namespace Menu_Helpers; edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead))); - edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker))); + if(!Profile->get_mixbus()) + edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker))); edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse))); + + set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2); } void Editor::build_edit_mode_menu () { using namespace Menu_Helpers; + + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide))); +// edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice))); + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple))); + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock))); - edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide))); -// edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice))); - edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple))); - edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock))); + set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2); } void @@ -3032,6 +3095,8 @@ Editor::build_snap_mode_menu () snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff))); snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal))); snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic))); + + set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2); } void @@ -3069,6 +3134,9 @@ Editor::build_snap_type_menu () snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd))); snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync))); snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary))); + + set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2); + } void @@ -3076,18 +3144,18 @@ Editor::setup_tooltips () { ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)")); ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)")); + ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)")); ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)")); - ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes")); - ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain")); - ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range")); + ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation")); ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes")); ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions")); - ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing")); + ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Select/move contents (notes and automation)")); ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations")); ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later")); ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier")); ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In")); ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out")); + ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale")); ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session")); ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus")); ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks")); @@ -3208,6 +3276,7 @@ void Editor::begin_reversible_command (string name) { if (_session) { + before.push_back (&_selection_memento->get_state ()); _session->begin_reversible_command (name); } } @@ -3216,6 +3285,7 @@ void Editor::begin_reversible_command (GQuark q) { if (_session) { + before.push_back (&_selection_memento->get_state ()); _session->begin_reversible_command (q); } } @@ -3224,6 +3294,14 @@ void Editor::commit_reversible_command () { if (_session) { + if (before.size() == 1) { + _session->add_command (new MementoCommand(*(_selection_memento), before.front(), &_selection_memento->get_state ())); + } + + if (!before.empty()) { + before.pop_back(); + } + _session->commit_reversible_command (); } } @@ -3335,7 +3413,7 @@ Editor::cycle_edit_mode () Config->set_edit_mode (Ripple); } break; -// case Splice: + case Splice: case Ripple: Config->set_edit_mode (Lock); break; @@ -3373,6 +3451,9 @@ Editor::snap_mode_selection_done (SnapMode mode) void Editor::cycle_edit_point (bool with_marker) { + if(Profile->get_mixbus()) + with_marker = false; + switch (_edit_point) { case EditAtMouse: set_edit_point_preference (EditAtPlayhead); @@ -3407,6 +3488,8 @@ Editor::build_zoom_focus_menu () zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead))); zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse))); zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit))); + + set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2); } void @@ -3423,18 +3506,56 @@ Editor::build_track_count_menu () { using namespace Menu_Helpers; - visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32))); - visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64))); - visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0))); + if (!Profile->get_mixbus()) { + visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks))); + visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0))); + } else { + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0))); + visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks))); + + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false))); + } +} + +void +Editor::set_zoom_preset (int64_t ms) +{ + if ( ms <= 0 ) { + temporal_zoom_session(); + return; + } + + ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate(); + temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width ); } void @@ -3454,15 +3575,21 @@ Editor::set_visible_track_count (int32_t n) int h; string str; - + if (_visible_track_count > 0) { - h = _visible_canvas_height / _visible_track_count; + h = trackviews_height() / _visible_track_count; std::ostringstream s; s << _visible_track_count; str = s.str(); } else if (_visible_track_count == 0) { - h = _visible_canvas_height / track_views.size(); - str = _("all"); + uint32_t n = 0; + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if ((*i)->marked_for_display()) { + ++n; + } + } + h = trackviews_height() / n; + str = _("All"); } else { /* negative value means that the visible track count has been overridden by explicit track height changes. @@ -3483,7 +3610,8 @@ Editor::set_visible_track_count (int32_t n) void Editor::override_visible_track_count () { - _visible_track_count = -_visible_track_count; + _visible_track_count = -1; + visible_tracks_selector.set_text ( _("*") ); } bool @@ -3718,6 +3846,25 @@ Editor::playlist_selector () const return *_playlist_selector; } +framecnt_t +Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration) +{ + if (paste_count == 0) { + /* don't bother calculating an offset that will be zero anyway */ + return 0; + } + + /* calculate basic unsnapped multi-paste offset */ + framecnt_t offset = paste_count * duration; + + /* snap offset so pos + offset is aligned to the grid */ + framepos_t offset_pos = pos + offset; + snap_to(offset_pos, RoundUpMaybe); + offset = offset_pos - pos; + + return offset; +} + Evoral::MusicalTime Editor::get_grid_type_as_beats (bool& success, framepos_t position) { @@ -3725,64 +3872,64 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position) switch (_snap_type) { case SnapToBeat: - return 1.0; + return Evoral::MusicalTime(1.0); break; case SnapToBeatDiv128: - return 1.0/128.0; + return Evoral::MusicalTime(1.0/128.0); break; case SnapToBeatDiv64: - return 1.0/64.0; + return Evoral::MusicalTime(1.0/64.0); break; case SnapToBeatDiv32: - return 1.0/32.0; + return Evoral::MusicalTime(1.0/32.0); break; case SnapToBeatDiv28: - return 1.0/28.0; + return Evoral::MusicalTime(1.0/28.0); break; case SnapToBeatDiv24: - return 1.0/24.0; + return Evoral::MusicalTime(1.0/24.0); break; case SnapToBeatDiv20: - return 1.0/20.0; + return Evoral::MusicalTime(1.0/20.0); break; case SnapToBeatDiv16: - return 1.0/16.0; + return Evoral::MusicalTime(1.0/16.0); break; case SnapToBeatDiv14: - return 1.0/14.0; + return Evoral::MusicalTime(1.0/14.0); break; case SnapToBeatDiv12: - return 1.0/12.0; + return Evoral::MusicalTime(1.0/12.0); break; case SnapToBeatDiv10: - return 1.0/10.0; + return Evoral::MusicalTime(1.0/10.0); break; case SnapToBeatDiv8: - return 1.0/8.0; + return Evoral::MusicalTime(1.0/8.0); break; case SnapToBeatDiv7: - return 1.0/7.0; + return Evoral::MusicalTime(1.0/7.0); break; case SnapToBeatDiv6: - return 1.0/6.0; + return Evoral::MusicalTime(1.0/6.0); break; case SnapToBeatDiv5: - return 1.0/5.0; + return Evoral::MusicalTime(1.0/5.0); break; case SnapToBeatDiv4: - return 1.0/4.0; + return Evoral::MusicalTime(1.0/4.0); break; case SnapToBeatDiv3: - return 1.0/3.0; + return Evoral::MusicalTime(1.0/3.0); break; case SnapToBeatDiv2: - return 1.0/2.0; + return Evoral::MusicalTime(1.0/2.0); break; case SnapToBar: if (_session) { - return _session->tempo_map().meter_at (position).divisions_per_bar(); + return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar()); } break; @@ -3801,7 +3948,7 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position) break; } - return 0.0; + return Evoral::MusicalTime(); } framecnt_t @@ -3932,6 +4079,14 @@ Editor::update_tearoff_visibility() } } +void +Editor::reattach_all_tearoffs () +{ + if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back (); + if (_tools_tearoff) _tools_tearoff->put_it_back (); + if (_zoom_tearoff) _zoom_tearoff->put_it_back (); +} + void Editor::maximise_editing_space () { @@ -3996,7 +4151,7 @@ Editor::copy_playlists (TimeAxisView* v) void Editor::clear_playlists (TimeAxisView* v) { - begin_reversible_command (_("clear playlists")); + begin_reversible_command (_("clear playlists")); vector > playlists; _session->playlists->get (playlists); mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id); @@ -4034,6 +4189,12 @@ Editor::on_key_release_event (GdkEventKey* ev) // return key_press_focus_accelerator_handler (*this, ev); } +double +Editor::get_y_origin () const +{ + return vertical_adjustment.get_value (); +} + /** Queue up a change to the viewport x origin. * @param frame New x origin. */ @@ -4056,8 +4217,6 @@ Editor::reset_y_origin (double y) void Editor::reset_zoom (framecnt_t spp) { - clamp_samples_per_pixel (spp); - if (spp == samples_per_pixel) { return; } @@ -4117,7 +4276,9 @@ Editor::undo_visual_state () redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false)); - use_visual_state (*vs); + if (vs) { + use_visual_state (*vs); + } } void @@ -4130,9 +4291,13 @@ Editor::redo_visual_state () VisualState* vs = redo_visual_stack.back(); redo_visual_stack.pop_back(); - undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false)); + // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? + // why do we check here? + undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false)); - use_visual_state (*vs); + if (vs) { + use_visual_state (*vs); + } } void @@ -4169,12 +4334,26 @@ Editor::use_visual_state (VisualState& vs) /** This is the core function that controls the zoom level of the canvas. It is called * whenever one or more calls are made to reset_zoom(). It executes in an idle handler. - * @param fpu New frames per unit; should already have been clamped so that it is sensible. + * @param spp new number of samples per pixel */ void Editor::set_samples_per_pixel (framecnt_t spp) { - clamp_samples_per_pixel (spp); + if (spp < 1) { + return; + } + + const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000); + const framecnt_t lots_of_pixels = 4000; + + /* if the zoom level is greater than what you'd get trying to display 3 + * days of audio on a really big screen, then it's too big. + */ + + if (spp * lots_of_pixels > three_days) { + return; + } + samples_per_pixel = spp; if (tempo_lines) { @@ -4227,7 +4406,8 @@ void Editor::ensure_visual_change_idle_handler () { if (pending_visual_change.idle_handler_id < 0) { - pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this); + // see comment in add_to_idle_resize above. + pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL); pending_visual_change.being_handled = false; } } @@ -4328,6 +4508,10 @@ Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_men framepos_t where = 0; EditPoint ep = _edit_point; + if(Profile->get_mixbus()) + if (ep == EditAtSelectedMarker) + ep=EditAtPlayhead; + if (from_context_menu && (ep == EditAtMouse)) { return canvas_event_sample (&context_click_event, 0, 0); } @@ -4420,8 +4604,7 @@ Editor::set_punch_range (framepos_t start, framepos_t end, string cmd) _session->set_auto_punch_location (loc); XMLNode &after = _session->locations()->get_state(); _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); - } - else { + } else { XMLNode &before = tpl->get_state(); tpl->set_hidden (false, this); tpl->set (start, end); @@ -4509,22 +4692,14 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie /** Get regions using the following method: * - * Make a region list using the selected regions, unless - * the edit point is `mouse' and the mouse is over an unselected - * region. In this case, use just that region. + * Make a region list using: + * (a) any selected regions + * (b) the intersection of any selected tracks and the edit point(*) + * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse * - * If the edit point is not 'mouse', and there are no regions selected, - * search the list of selected tracks and return regions that are under - * the edit point on these tracks. If there are no selected tracks and - * 'No Selection = All Tracks' is active, search all tracks, + * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks * - * The rationale here is that the mouse edit point is special in that - * its position describes both a time and a track; the other edit - * modes only describe a time. Hence if the edit point is `mouse' we - * ignore selected tracks, as we assume the user means something by - * pointing at a particular track. Also in this case we take note of - * the region directly under the edit point, as there is always just one - * (rather than possibly several with non-mouse edit points). + * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive */ RegionSelection @@ -4532,23 +4707,15 @@ Editor::get_regions_from_selection_and_edit_point () { RegionSelection regions; - if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) { + if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) { regions.add (entered_regionview); } else { regions = selection->regions; } - - if (regions.empty() && _edit_point != EditAtMouse) { + if ( regions.empty() ) { TrackViewList tracks = selection->tracks; - if (_route_groups->all_group_active_button().get_active() && tracks.empty()) { - /* tracks is empty (no track selected), and 'No Selection = All Tracks' - * is enabled, so consider all tracks - */ - tracks = track_views; - } - if (!tracks.empty()) { /* no region selected or entered, but some selected tracks: * act on all regions on the selected tracks at the edit point @@ -4557,6 +4724,43 @@ Editor::get_regions_from_selection_and_edit_point () get_regions_at(regions, where, tracks); } } + + return regions; +} + +/** Get regions using the following method: + * + * Make a region list using: + * (a) any selected regions + * (b) the intersection of any selected tracks and the edit point(*) + * (c) if neither exists, then whatever region is under the mouse + * + * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks + * + * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive + */ +RegionSelection +Editor::get_regions_from_selection_and_mouse (framepos_t pos) +{ + RegionSelection regions; + + if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) { + regions.add (entered_regionview); + } else { + regions = selection->regions; + } + + if ( regions.empty() ) { + TrackViewList tracks = selection->tracks; + + if (!tracks.empty()) { + /* no region selected or entered, but some selected tracks: + * act on all regions on the selected tracks at the edit point + */ + get_regions_at(regions, pos, tracks); + } + } + return regions; } @@ -4577,6 +4781,35 @@ Editor::get_regions_from_selection_and_entered () return regions; } +void +Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* tatv; + + if ((tatv = dynamic_cast (*i)) != 0) { + boost::shared_ptr pl; + std::vector > results; + boost::shared_ptr tr; + + if ((tr = tatv->track()) == 0) { + /* bus */ + continue; + } + + if ((pl = (tr->playlist())) != 0) { + boost::shared_ptr r = pl->region_by_id (id); + if (r) { + RegionView* marv = tatv->view()->find_view (r); + if (marv) { + regions.push_back (marv); + } + } + } + } + } +} + void Editor::get_regions_corresponding_to (boost::shared_ptr region, vector& regions, bool src_comparison) { @@ -4662,7 +4895,11 @@ void Editor::add_to_idle_resize (TimeAxisView* view, int32_t h) { if (resize_idle_id < 0) { - resize_idle_id = g_idle_add (_idle_resize, this); + /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS + * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations. + * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.) + */ + resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL); _pending_resize_amount = 0; } @@ -4732,8 +4969,15 @@ Editor::located () } void -Editor::region_view_added (RegionView *) +Editor::region_view_added (RegionView * rv) { + for (list::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) { + if (rv->region ()->id () == (*pr)) { + selection->add (rv); + selection->regions.pending.erase (pr); + break; + } + } _summary->set_background_dirty (); } @@ -4822,12 +5066,6 @@ Editor::add_routes (RouteList& routes) rtv->effective_gain_display (); - if (internal_editing()) { - rtv->enter_internal_edit_mode (); - } else { - rtv->leave_internal_edit_mode (); - } - rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed)); } @@ -5085,11 +5323,11 @@ Editor::scroll_press (Direction dir) break; case UP: - scroll_tracks_up_line (); + scroll_up_one_track (); break; case DOWN: - scroll_tracks_down_line (); + scroll_down_one_track (); break; }