X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=ce6e6b15ae5ca0a32b5617fa46a983b4b69a8a6b;hb=57c1b6e261076cae9b61e74aa0aff47a9f296c0f;hp=436b8a250cd641eddb29ee1b9ff0f7bbeae021d7;hpb=2d82446f596b30ae6ffcf464fb63aa6e44e43355;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 436b8a250c..ce6e6b15ae 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -45,6 +45,7 @@ #include "pbd/unknown_type.h" #include "pbd/unwind.h" #include "pbd/stacktrace.h" +#include "pbd/timersub.h" #include #include @@ -120,11 +121,13 @@ #include "tempo_lines.h" #include "time_axis_view.h" #include "utils.h" +#include "verbose_cursor.h" #include "i18n.h" using namespace std; using namespace ARDOUR; +using namespace ARDOUR_UI_UTILS; using namespace PBD; using namespace Gtk; using namespace Glib; @@ -139,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"), @@ -185,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"), @@ -208,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) { @@ -261,7 +274,6 @@ Editor::Editor () /* tool bar related */ - , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true)) , toolbar_selection_clock_table (2,3) , _mouse_mode_tearoff (0) , automation_mode_button (_("mode")) @@ -300,13 +312,18 @@ 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; current_mixer_strip = 0; tempo_lines = 0; 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); @@ -373,24 +390,22 @@ 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()->get_LocationMarker(); + location_range_color = ARDOUR_UI::config()->get_LocationRange(); + location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker(); + location_loop_color = ARDOUR_UI::config()->get_LocationLoop(); + location_punch_color = ARDOUR_UI::config()->get_LocationPunch(); 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 () */ _scroll_callbacks = 0; - zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed)); - bbt_label.set_name ("EditorRulerLabel"); bbt_label.set_size_request (-1, (int)timebar_height); bbt_label.set_alignment (1.0, 0.5); @@ -469,9 +484,10 @@ Editor::Editor () transport_mark_label.hide(); transport_mark_label.set_no_show_all(); - initialize_rulers (); 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)); @@ -495,13 +511,13 @@ Editor::Editor () controls_layout.add (*h); controls_layout.set_name ("EditControlsBase"); - controls_layout.add_events (Gdk::SCROLL_MASK); - controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false); - - controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); + controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK); controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release)); + controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false); _cursors = new MouseCursors; + _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set()); + cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl; ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ()); @@ -513,38 +529,22 @@ Editor::Editor () // CAIROCANVAS time_pad->show(); - time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2); - time_canvas_vbox.set_size_request (-1, -1); - - ruler_label_event_box.add (ruler_label_vbox); - ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); - ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); - - time_bars_event_box.add (time_bars_vbox); - time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); - time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); - - time_canvas_event_box.add (time_canvas_vbox); - time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK); - edit_packer.set_col_spacings (0); edit_packer.set_row_spacings (0); edit_packer.set_homogeneous (false); edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); - /* labels for the rulers */ - edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0); - /* labels for the marker "tracks" (time bars) */ - edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0); - /* the rulers */ - edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0); + time_bars_event_box.add (time_bars_vbox); + time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); + time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); + + /* labels for the time bars */ + edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0); /* track controls */ - edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0); - /* time bars canvas */ - edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0); - /* track canvas */ - edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); + edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0); + /* canvas */ + edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0); bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); @@ -555,6 +555,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 ()); @@ -677,11 +683,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"); @@ -751,6 +755,7 @@ Editor::Editor () Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1)); Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context()); + ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed)); TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); @@ -758,8 +763,9 @@ Editor::Editor () _last_region_menu_was_main = false; _popup_region_menu_item = 0; + _ignore_follow_edits = false; + _show_marker_lines = false; - _over_region_trim_target = false; /* Button bindings */ @@ -773,9 +779,14 @@ Editor::Editor () } constructed = true; - instant_save (); + + /* grab current parameter state */ + boost::function pc (boost::bind (&Editor::ui_parameter_changed, this, _1)); + ARDOUR_UI::config()->map_parameters (pc); setup_fade_images (); + + instant_save (); } Editor::~Editor() @@ -783,9 +794,9 @@ Editor::~Editor() delete button_bindings; delete _routes; delete _route_groups; - delete _time_bars_canvas_viewport; delete _track_canvas_viewport; delete _drags; + delete nudge_clock; } XMLNode* @@ -802,16 +813,28 @@ 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 { - return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() ); + return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active()); } void @@ -836,8 +859,6 @@ Editor::catch_vanishing_regionview (RegionView *rv) if (!_all_region_actions_sensitized) { sensitize_all_region_actions (true); } - - _over_region_trim_target = false; } void @@ -851,7 +872,9 @@ Editor::set_entered_regionview (RegionView* rv) entered_regionview->exited (); } - if ((entered_regionview = rv) != 0) { + entered_regionview = rv; + + if (entered_regionview != 0) { entered_regionview->entered (internal_editing ()); } @@ -870,7 +893,9 @@ Editor::set_entered_track (TimeAxisView* tav) entered_track->exited (); } - if ((entered_track = tav) != 0) { + entered_track = tav; + + if (entered_track) { entered_track->entered (); } } @@ -879,6 +904,7 @@ void Editor::show_window () { if (!is_visible ()) { + DisplaySuspender ds; show_all (); /* XXX: this is a bit unfortunate; it would probably @@ -905,7 +931,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"); } } @@ -926,23 +952,6 @@ Editor::instant_save () } } -void -Editor::zoom_adjustment_changed () -{ - if (_session == 0) { - return; - } - - framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width); - bool clamped = clamp_samples_per_pixel (fpu); - - if (clamped) { - zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width)); - } - - temporal_zoom (fpu); -} - void Editor::control_vertical_zoom_in_all () { @@ -1056,12 +1065,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 */ @@ -1123,6 +1132,79 @@ Editor::on_realize () { Window::on_realize (); Realized (); + + if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) { + start_lock_event_timing (); + } + + signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler)); +} + +void +Editor::start_lock_event_timing () +{ + /* check if we should lock the GUI every 30 seconds */ + + Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000); +} + +bool +Editor::generic_event_handler (GdkEvent* ev) +{ + switch (ev->type) { + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_MOTION_NOTIFY: + case GDK_KEY_PRESS: + 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; +} + +bool +Editor::lock_timeout_callback () +{ + struct timeval now, delta; + + gettimeofday (&now, 0); + + timersub (&now, &last_event_time, &delta); + + 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. + + unlock() will call start_lock_event_timing() to get things + started again. + */ + return false; + } + + return true; } void @@ -1206,7 +1288,6 @@ Editor::set_session (Session *t) return; } - zoom_range_clock->set_session (_session); _playlist_selector->set_session (_session); nudge_clock->set_session (_session); _summary->set_session (_session); @@ -1277,7 +1358,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 (); @@ -1719,6 +1799,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))); @@ -1809,7 +1892,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()); @@ -1886,7 +1969,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()); @@ -2021,13 +2104,16 @@ 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); } - set_canvas_cursor (); + reset_canvas_cursor (); if (!force && !changed) { return; @@ -2117,7 +2203,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); } @@ -2424,19 +2515,29 @@ Editor::get_state () return *node; } - - -/** @param y y offset from the top of all trackviews. +/** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units + * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units + * * @return pair: TimeAxisView that y is over, layer index. + * * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is * in stacked or expanded region display mode, otherwise 0. */ std::pair -Editor::trackview_by_y_position (double y) +Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const { - for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { + if (!trackview_relative_offset) { + y -= _trackview_group->canvas_origin().y; + } + + if (y < 0) { + return std::make_pair ( (TimeAxisView *) 0, 0); + } + for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { + std::pair const r = (*iter)->covers_y_position (y); + if (r.first) { return r; } @@ -2451,7 +2552,7 @@ Editor::trackview_by_y_position (double y) * @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; @@ -2469,7 +2570,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; @@ -2479,14 +2580,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()); @@ -2499,7 +2603,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; @@ -2518,7 +2625,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; @@ -2531,12 +2641,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; @@ -2551,7 +2661,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); @@ -2559,7 +2672,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; @@ -2567,7 +2683,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; @@ -2721,26 +2840,43 @@ 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); - /* make them just a bit bigger */ - mouse_move_button.set_size_request (-1, 30); + 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); + + 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); @@ -2750,14 +2886,17 @@ 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 (internal_edit_button, false, false, 0); } mouse_mode_vbox->pack_start (*mouse_mode_hbox); @@ -2767,15 +2906,7 @@ Editor::setup_toolbar () mouse_mode_box->pack_start (*mouse_mode_align, false, false); - edit_mode_strings.push_back (edit_mode_to_string (Slide)); - if (!Profile->get_sae()) { - edit_mode_strings.push_back (edit_mode_to_string (Splice)); - } - edit_mode_strings.push_back (edit_mode_to_string (Lock)); - 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); @@ -2786,7 +2917,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); } @@ -2806,67 +2937,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)); @@ -2881,20 +3013,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); @@ -2909,9 +3039,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); @@ -2920,13 +3047,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); } @@ -2939,7 +3066,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); @@ -2950,7 +3077,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); @@ -2978,18 +3105,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(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 @@ -3000,6 +3133,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 @@ -3037,6 +3172,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 @@ -3044,10 +3182,10 @@ 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_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")); @@ -3056,6 +3194,7 @@ Editor::setup_tooltips () 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")); @@ -3300,10 +3439,11 @@ Editor::cycle_edit_mode () if (Profile->get_sae()) { Config->set_edit_mode (Lock); } else { - Config->set_edit_mode (Splice); + Config->set_edit_mode (Ripple); } break; case Splice: + case Ripple: Config->set_edit_mode (Lock); break; case Lock: @@ -3340,6 +3480,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); @@ -3374,6 +3517,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 @@ -3390,18 +3535,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 @@ -3421,15 +3604,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. @@ -3450,7 +3639,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 @@ -3685,6 +3875,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) { @@ -3692,64 +3901,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; @@ -3768,7 +3977,7 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position) break; } - return 0.0; + return Evoral::MusicalTime(); } framecnt_t @@ -3871,26 +4080,14 @@ Editor::transport_punch_location() bool Editor::control_layout_scroll (GdkEventScroll* ev) { - if (Keyboard::some_magic_widget_has_focus()) { - return false; - } - - switch (ev->direction) { - case GDK_SCROLL_UP: - scroll_tracks_up_line (); - return true; - break; + /* Just forward to the normal canvas scroll method. The coordinate + systems are different but since the canvas is always larger than the + track headers, and aligned with the trackview area, this will work. - case GDK_SCROLL_DOWN: - scroll_tracks_down_line (); - return true; - - default: - /* no left/right handling yet */ - break; - } - - return false; + In the not too distant future this layout is going away anyway and + headers will be on the canvas. + */ + return canvas_scroll_event (ev, false); } void @@ -3911,6 +4108,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 () { @@ -4035,8 +4240,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; } @@ -4096,7 +4299,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 @@ -4109,9 +4314,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 @@ -4128,8 +4337,7 @@ void Editor::use_visual_state (VisualState& vs) { PBD::Unwinder nsv (no_save_visual, true); - - _routes->suspend_redisplay (); + DisplaySuspender ds; vertical_adjustment.set_value (vs.y_position); @@ -4145,29 +4353,34 @@ Editor::use_visual_state (VisualState& vs) } _routes->update_visibility (); - _routes->resume_redisplay (); } /** 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); - samples_per_pixel = spp; - - if (tempo_lines) { - tempo_lines->tempo_map_changed(); + if (spp < 1) { + return; } - /* convert fpu to frame count */ + const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000); + const framecnt_t lots_of_pixels = 4000; - framepos_t frames = samples_per_pixel * _visible_canvas_width; + /* 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 (samples_per_pixel != zoom_range_clock->current_duration()) { - zoom_range_clock->set (frames); + if (spp * lots_of_pixels > three_days) { + return; + } + + samples_per_pixel = spp; + + if (tempo_lines) { + tempo_lines->tempo_map_changed(); } bool const showing_time_selection = selection->time.length() > 0; @@ -4182,10 +4395,6 @@ Editor::set_samples_per_pixel (framecnt_t spp) ArdourCanvas::GtkCanvasViewport* c; - c = get_time_bars_canvas(); - if (c) { - c->canvas()->zoomed (); - } c = get_track_canvas(); if (c) { c->canvas()->zoomed (); @@ -4220,7 +4429,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; } } @@ -4321,6 +4531,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); } @@ -4502,22 +4716,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 @@ -4525,23 +4731,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 @@ -4550,6 +4748,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; } @@ -4655,7 +4890,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; } @@ -4727,13 +4966,13 @@ Editor::located () void Editor::region_view_added (RegionView *) { - _summary->set_dirty (); + _summary->set_background_dirty (); } void Editor::region_view_removed () { - _summary->set_dirty (); + _summary->set_background_dirty (); } RouteTimeAxisView* @@ -4767,6 +5006,22 @@ Editor::axis_views_from_routes (boost::shared_ptr r) const return t; } +void +Editor::suspend_route_redisplay () +{ + if (_routes) { + _routes->suspend_redisplay(); + } +} + +void +Editor::resume_route_redisplay () +{ + if (_routes) { + _routes->resume_redisplay(); + } +} + void Editor::add_routes (RouteList& routes) { @@ -4824,6 +5079,10 @@ Editor::add_routes (RouteList& routes) void Editor::timeaxisview_deleted (TimeAxisView *tv) { + if (tv == entered_track) { + entered_track = 0; + } + if (_session && _session->deletion_in_progress()) { /* the situation is under control */ return; @@ -4835,10 +5094,6 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) _routes->route_removed (tv); - if (tv == entered_track) { - entered_track = 0; - } - TimeAxisView::Children c = tv->get_child_list (); for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) { if (entered_track == i->get()) { @@ -5062,11 +5317,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; } @@ -5270,7 +5525,6 @@ Editor::session_going_away () } track_views.clear (); - zoom_range_clock->set_session (0); nudge_clock->set_session (0); editor_list_button.set_active(false); @@ -5447,3 +5701,18 @@ Editor::zoom_vertical_modifier_released() { _stepping_axis_view = 0; } + +void +Editor::ui_parameter_changed (string parameter) +{ + if (parameter == "icon-set") { + while (!_cursor_stack.empty()) { + _cursor_stack.pop(); + } + _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set()); + } else if (parameter == "draggable-playhead") { + if (_verbose_cursor) { + playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead()); + } + } +}