X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=7aaeb466780db1e8e1b5b671f85a4496796427fc;hb=e7c85706e5553181636e7052f2fe10469b57fd85;hp=5826ba0b7f3e6479103d87ed590304849b67f4ff;hpb=482873760c11f4a69a7bcf0e014be91800e97f57;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 5826ba0b7f..7aaeb46678 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -72,11 +72,13 @@ #include "ardour/lmath.h" #include "ardour/location.h" #include "ardour/profile.h" +#include "ardour/route.h" #include "ardour/route_group.h" #include "ardour/session_playlists.h" #include "ardour/tempo.h" #include "ardour/utils.h" #include "ardour/vca_manager.h" +#include "ardour/vca.h" #include "canvas/debug.h" #include "canvas/text.h" @@ -85,6 +87,7 @@ #include "actions.h" #include "analysis_window.h" +#include "ardour_spacer.h" #include "audio_clock.h" #include "audio_region_view.h" #include "audio_streamview.h" @@ -109,7 +112,6 @@ #include "gui_object.h" #include "gui_thread.h" #include "keyboard.h" -#include "keyeditor.h" #include "luainstance.h" #include "marker.h" #include "midi_region_view.h" @@ -124,11 +126,13 @@ #include "region_layering_order_editor.h" #include "rgb_macros.h" #include "rhythm_ferret.h" +#include "route_sorter.h" #include "selection.h" #include "simple_progress_dialog.h" #include "sfdb_ui.h" #include "tempo_lines.h" #include "time_axis_view.h" +#include "time_info_box.h" #include "timers.h" #include "tooltips.h" #include "ui_config.h" @@ -136,7 +140,7 @@ #include "vca_time_axis.h" #include "verbose_cursor.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -234,35 +238,12 @@ static const gchar *_rb_opt_strings[] = { #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) -{ - /* if the handle of a pane vanishes into (at least) the tabs of a notebook, - it is: - - X: hard to access - Quartz: impossible to access - - so stop that by preventing it from ever getting too narrow. 35 - pixels is basically a rough guess at the tab width. - - ugh. - */ - - int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35; - - gint pos = pane->get_position (); - - if (pos > max_width_of_lhs) { - pane->set_position (max_width_of_lhs); - } -} - Editor::Editor () : PublicEditor (global_hpacker) , editor_mixer_strip_width (Wide) , constructed (false) , _playlist_selector (0) + , _time_info_box (0) , no_save_visual (false) , leftmost_frame (0) , samples_per_pixel (2048) @@ -405,14 +386,13 @@ Editor::Editor () , _visible_track_count (-1) , toolbar_selection_clock_table (2,3) , automation_mode_button (_("mode")) - , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10))) , selection (new Selection (this)) , cut_buffer (new Selection (this)) , _selection_memento (new SelectionMemento()) , _all_region_actions_sensitized (false) , _ignore_region_action (false) , _last_region_menu_was_main (false) - , _ignore_follow_edits (false) + , _track_selection_change_without_scroll (false) , cd_marker_bar_drag_rect (0) , range_bar_drag_rect (0) , transport_bar_drag_rect (0) @@ -593,12 +573,11 @@ Editor::Editor () initialize_canvas (); - CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus)); + CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus)); _summary = new EditorSummary (this); selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed)); - selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed)); editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed)); @@ -664,6 +643,7 @@ Editor::Editor () _regions = new EditorRegions (this); _snapshots = new EditorSnapshots (this); _locations = new EditorLocations (this); + _time_info_box = new TimeInfoBox (true); /* these are static location signals */ @@ -685,7 +665,18 @@ Editor::Editor () _notebook_shrunk = false; - editor_summary_pane.pack1(edit_packer); + + /* Pick up some settings we need to cache, early */ + + XMLNode* settings = ARDOUR_UI::instance()->editor_settings(); + XMLProperty* prop; + + if (settings && (prop = settings->property ("notebook-shrunk"))) { + _notebook_shrunk = string_is_affirmative (prop->value ()); + } + + editor_summary_pane.set_check_divider_position (true); + editor_summary_pane.add (edit_packer); Button* summary_arrows_left_left = manage (new Button); summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE))); @@ -726,31 +717,62 @@ Editor::Editor () _summary_hbox.pack_start (*summary_arrows_right, false, false); if (!ARDOUR::Profile->get_trx()) { - editor_summary_pane.pack2 (_summary_hbox); + editor_summary_pane.add (_summary_hbox); } - edit_pane.pack1 (editor_summary_pane, true, true); + edit_pane.set_check_divider_position (true); + edit_pane.add (editor_summary_pane); if (!ARDOUR::Profile->get_trx()) { - edit_pane.pack2 (_the_notebook, false, true); + _editor_list_vbox.pack_start (*_time_info_box, false, false, 0); + _editor_list_vbox.pack_start (_the_notebook); + edit_pane.add (_editor_list_vbox); + edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */ } - editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast (&editor_summary_pane))); + edit_pane.set_drag_cursor (*_cursors->expand_left_right); + editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down); + + float fract; + + { + LocaleGuard lg; + + if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) { + /* initial allocation is 90% to canvas, 10% to notebook */ + edit_pane.set_divider (0, 0.90); + } else { + edit_pane.set_divider (0, fract); + } + + if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) { + /* initial allocation is 90% to canvas, 10% to summary */ + editor_summary_pane.set_divider (0, 0.90); + } else { + + editor_summary_pane.set_divider (0, fract); + } + } - /* XXX: editor_summary_pane might need similar to the edit_pane */ + global_vpacker.set_spacing (2); + global_vpacker.set_border_width (0); - edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); + //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. - Glib::PropertyProxy proxy = edit_pane.property_position(); - proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast (&edit_pane))); + Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box + ebox->set_name("EditorWindow"); + ebox->add (toolbar_hbox); - top_hbox.pack_start (toolbar_frame); + Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box + epane_box->set_name("EditorWindow"); + epane_box->add (edit_pane); - HBox *hbox = manage (new HBox); - hbox->pack_start (edit_pane, true, true); + Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box + epane_box2->set_name("EditorWindow"); + epane_box2->add (global_vpacker); - global_vpacker.pack_start (top_hbox, false, false); - global_vpacker.pack_start (*hbox, true, true); - global_hpacker.pack_start (global_vpacker, true, true); + global_vpacker.pack_start (*ebox, false, false); + global_vpacker.pack_start (*epane_box, true, true); + global_hpacker.pack_start (*epane_box2, true, true); /* need to show the "contents" widget so that notebook will show if tab is switched to */ @@ -823,8 +845,6 @@ Editor::Editor () _last_region_menu_was_main = false; _popup_region_menu_item = 0; - _ignore_follow_edits = false; - _show_marker_lines = false; /* Button bindings */ @@ -846,20 +866,18 @@ Editor::Editor () setup_fade_images (); - LuaInstance::instance(); // instantiate - LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name)); - instant_save (); } Editor::~Editor() { - delete button_bindings; + delete button_bindings; delete _routes; delete _route_groups; delete _track_canvas_viewport; delete _drags; delete nudge_clock; + delete _verbose_cursor; delete quantize_dialog; delete _summary; delete _group_tabs; @@ -867,10 +885,22 @@ Editor::~Editor() delete _snapshots; delete _locations; delete _playlist_selector; + delete _time_info_box; + delete selection; + delete cut_buffer; + delete _cursors; + + LuaInstance::destroy_instance (); for (list::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) { delete *i; } + for (std::map::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) { + delete i->second; + } + for (std::map::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) { + delete i->second; + } } XMLNode* @@ -1006,42 +1036,9 @@ Editor::control_unselect () } void -Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op) +Editor::control_select (boost::shared_ptr s, Selection::Operation op) { - /* handles the (static) signal from the ControlProtocol class that - * requests setting the selected track to a given RID - */ - - if (!_session) { - return; - } - - PresentationInfo::Flag select_flags; - - if (global_order & ~0xffffffff) { - /* some flags are set, so the PresentationInfo constructor - * will use them - */ - select_flags = PresentationInfo::Flag (0); - } else { - /* no type flags set in the global order ID, so assume caller - * wants to select a Route - */ - select_flags = PresentationInfo::Route; - } - - PresentationInfo pi (global_order, select_flags); - boost::shared_ptr s = _session->get_remote_nth_stripable (pi.group_order(), pi.flags()); - - /* selected object may not be a Route */ - - boost::shared_ptr r = boost::dynamic_pointer_cast (s); - - if (!r) { - return; - } - - TimeAxisView* tav = axis_view_from_route (r); + TimeAxisView* tav = axis_view_from_stripable (s); if (tav) { switch (op) { @@ -1207,7 +1204,7 @@ Editor::generic_event_handler (GdkEvent* ev) /* leaving window, so reset focus, thus ending any and all text entry operations. */ - reset_focus (&contents()); + ARDOUR_UI::instance()->reset_focus (&contents()); break; } break; @@ -1337,6 +1334,7 @@ Editor::set_session (Session *t) _snapshots->set_session (_session); _routes->set_session (_session); _locations->set_session (_session); + _time_info_box->set_session (_session); if (rhythm_ferret) { rhythm_ferret->set_session (_session); @@ -1393,7 +1391,7 @@ Editor::set_session (Session *t) _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context()); _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context()); _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context()); - _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context()); + _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context()); _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context()); _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context()); _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context()); @@ -1432,34 +1430,34 @@ Editor::set_session (Session *t) break; } + /* catch up on selection of stripables (other selection state is lost + * when a session is closed + */ + + StripableList sl; + TrackViewList tl; + _session->get_stripables (sl); + for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) { + if ((*s)->presentation_info().selected()) { + RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id()); + if (rtav) { + tl.push_back (rtav); + } + } + } + if (!tl.empty()) { + selection->set (tl); + } + /* 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)); - LuaInstance::instance()->set_session(_session); start_updating_meters (); } -void -Editor::action_pre_activated (Glib::RefPtr const & a) -{ - if (a->get_name() == "RegionMenu") { - /* When the main menu's region menu is opened, we setup the actions so that they look right - in the menu. I can't find a way of getting a signal when this menu is subsequently closed, - so we resensitize all region actions when the entered regionview or the region selection - changes. HOWEVER we can't always resensitize on entered_regionview change because that - happens after the region context menu is opened. So we set a flag here, too. - - What a carry on :( - */ - sensitize_the_right_region_actions (); - _last_region_menu_was_main = true; - } -} - void Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start) { @@ -1687,7 +1685,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, /* When the region menu is opened, we setup the actions so that they look right in the menu. */ - sensitize_the_right_region_actions (); + sensitize_the_right_region_actions (false); _last_region_menu_was_main = false; menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true)); @@ -1924,7 +1922,7 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::sha _popup_region_menu_item->set_label (menu_item_name); } - /* No latering allowed in later is higher layering model */ + /* No layering allowed in later is higher layering model */ RefPtr act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering")); if (act && Config->get_layer_model() == LaterHigher) { act->set_sensitive (false); @@ -1953,7 +1951,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) 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 (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal))); edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection))); @@ -2245,10 +2243,8 @@ Editor::set_snap_to (SnapType st) case SnapToBeatDiv4: case SnapToBeatDiv3: case SnapToBeatDiv2: { - std::vector grid; - compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples()); - compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples()); - update_tempo_based_rulers (grid); + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples()); + update_tempo_based_rulers (); break; } @@ -2337,6 +2333,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) } reset_canvas_action_sensitivity (in_track_canvas); + sensitize_the_right_region_actions (false); instant_save (); } @@ -2347,6 +2344,7 @@ Editor::set_state (const XMLNode& node, int version) XMLProperty const * prop; set_id (node); PBD::Unwinder nsi (no_save_instant, true); + LocaleGuard lg; Tabbable::set_state (node, version); @@ -2369,6 +2367,8 @@ Editor::set_state (const XMLNode& node, int version) if ((prop = node.property ("zoom-focus"))) { zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus)); + } else { + zoom_focus_selection_done (zoom_focus); } if ((prop = node.property ("zoom"))) { @@ -2386,6 +2386,8 @@ Editor::set_state (const XMLNode& node, int version) if ((prop = node.property ("snap-to"))) { snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type)); set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type)); + } else { + set_snap_to (_snap_type); } if ((prop = node.property ("snap-mode"))) { @@ -2395,6 +2397,8 @@ Editor::set_state (const XMLNode& node, int version) * which does not trigger set_text(). */ set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode)); + } else { + set_snap_mode (_snap_mode); } if ((prop = node.property ("internal-snap-to"))) { @@ -2447,6 +2451,8 @@ Editor::set_state (const XMLNode& node, int version) if ((prop = node.property ("edit-point"))) { set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); + } else { + set_edit_point_preference (_edit_point); } if ((prop = node.property ("show-measures"))) { @@ -2515,6 +2521,7 @@ Editor::set_state (const XMLNode& node, int version) for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { selection->set_state (**i, Stateful::current_state_version); _regions->set_state (**i); + _locations->set_state (**i); } if ((prop = node.property ("maximised"))) { @@ -2581,16 +2588,17 @@ Editor::get_state () { XMLNode* node = new XMLNode (X_("Editor")); char buf[32]; + LocaleGuard lg; id().print (buf, sizeof (buf)); node->add_property ("id", buf); node->add_child_nocopy (Tabbable::get_state()); - snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (edit_pane, false)); + snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ()); node->add_property("edit-horizontal-pane-pos", string(buf)); node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0"); - snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (editor_summary_pane, true)); + snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider()); node->add_property("edit-vertical-pane-pos", string(buf)); maybe_add_mixer_strip_width (*node); @@ -2655,6 +2663,7 @@ Editor::get_state () node->add_child_nocopy (LuaInstance::instance()->get_action_state()); node->add_child_nocopy (LuaInstance::instance()->get_hook_state()); + node->add_child_nocopy (_locations->get_state ()); return *node; } @@ -2696,7 +2705,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, RoundMode direction, bool for_mark) +Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark) { if (!_session || !event) { return; @@ -2705,6 +2714,8 @@ Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundM if (ArdourKeyboard::indicates_snap (event->button.state)) { if (_snap_mode == SnapOff) { snap_to_internal (start, direction, for_mark); + } else { + start.set (start.frame, 0); } } else { if (_snap_mode != SnapOff) { @@ -2712,14 +2723,17 @@ Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundM } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) { /* SnapOff, but we pressed the snap_delta modifier */ snap_to_internal (start, direction, for_mark); + } else { + start.set (start.frame, 0); } } } void -Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap) +Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap) { if (!_session || (_snap_mode == SnapOff && !ensure_snap)) { + start.set (start.frame, 0); return; } @@ -2727,20 +2741,21 @@ Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ens } void -Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/) +Editor::timecode_snap_to_internal (MusicFrame& pos, 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); + framepos_t start = pos.frame; + const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame()); + framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60); switch (_snap_type) { case SnapToTimecodeFrame: if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && - fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) { + fmod((double)start, (double)_session->samples_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 if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) { + start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame()); } else { - start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame()); + start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame()); } break; @@ -2790,14 +2805,16 @@ Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg; abort(); /*NOTREACHED*/ } + + pos.set (start, 0); } void -Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap) +Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap) { const framepos_t one_second = _session->frame_rate(); const framepos_t one_minute = _session->frame_rate() * 60; - framepos_t presnap = start; + framepos_t presnap = start.frame; framepos_t before; framepos_t after; @@ -2809,95 +2826,104 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, case SnapToCDFrame: if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && - start % (one_second/75) == 0) { + start.frame % (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 if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) { + start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75); } else { - start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75); + start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75); } + + start.set (start.frame, 0); + break; case SnapToSeconds: if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && - start % one_second == 0) { + start.frame % 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 if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) { + start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second; } else { - start = (framepos_t) floor ((double) start / one_second) * one_second; + start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second; } + + start.set (start.frame, 0); + break; case SnapToMinutes: if ((direction == RoundUpMaybe || direction == RoundDownMaybe) && - start % one_minute == 0) { + start.frame % 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 if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) { + start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute; } else { - start = (framepos_t) floor ((double) start / one_minute) * one_minute; + start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute; } + + start.set (start.frame, 0); + break; case SnapToBar: - start = _session->tempo_map().round_to_bar (start, direction); + start = _session->tempo_map().round_to_bar (start.frame, direction); break; case SnapToBeat: - start = _session->tempo_map().round_to_beat (start, direction); + start = _session->tempo_map().round_to_beat (start.frame, direction); break; case SnapToBeatDiv128: - start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction); break; case SnapToBeatDiv64: - start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction); break; case SnapToBeatDiv32: - start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction); break; case SnapToBeatDiv28: - start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction); break; case SnapToBeatDiv24: - start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction); break; case SnapToBeatDiv20: - start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction); break; case SnapToBeatDiv16: - start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction); break; case SnapToBeatDiv14: - start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction); break; case SnapToBeatDiv12: - start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction); break; case SnapToBeatDiv10: - start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction); break; case SnapToBeatDiv8: - start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction); break; case SnapToBeatDiv7: - start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction); break; case SnapToBeatDiv6: - start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction); break; case SnapToBeatDiv5: - start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction); break; case SnapToBeatDiv4: - start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction); break; case SnapToBeatDiv3: - start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction); break; case SnapToBeatDiv2: - start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction); + start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction); break; case SnapToMark: @@ -2905,24 +2931,31 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, return; } - _session->locations()->marks_either_side (start, before, after); + _session->locations()->marks_either_side (start.frame, before, after); if (before == max_framepos && after == max_framepos) { /* No marks to snap to, so just don't snap */ return; } else if (before == max_framepos) { - start = after; + start.frame = after; } else if (after == max_framepos) { - start = before; + start.frame = before; } else if (before != max_framepos && after != max_framepos) { - /* have before and after */ - if ((start - before) < (after - start)) { - start = before; - } else { - start = after; + if ((direction == RoundUpMaybe || direction == RoundUpAlways)) + start.frame = after; + else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) + start.frame = before; + else if (direction == 0 ) { + if ((start.frame - before) < (after - start.frame)) { + start.frame = before; + } else { + start.frame = after; + } } } + start.set (start.frame, 0); + break; case SnapToRegionStart: @@ -2935,9 +2968,9 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, vector::iterator next = region_boundary_cache.end (); if (direction > 0) { - next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); + next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame); } else { - next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); + next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame); } if (next != region_boundary_cache.begin ()) { @@ -2948,12 +2981,15 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev; framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next; - if (start > (p + n) / 2) { - start = n; + if (start.frame > (p + n) / 2) { + start.frame = n; } else { - start = p; + start.frame = p; } } + + start.set (start.frame, 0); + break; } @@ -2967,21 +3003,20 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, return; } - if (presnap > start) { - if (presnap > (start + pixel_to_sample(snap_threshold))) { - start = presnap; + if (presnap > start.frame) { + if (presnap > (start.frame + pixel_to_sample(snap_threshold))) { + start.set (presnap, 0); } - } else if (presnap < start) { - if (presnap < (start - pixel_to_sample(snap_threshold))) { - start = presnap; + } else if (presnap < start.frame) { + if (presnap < (start.frame - pixel_to_sample(snap_threshold))) { + start.set (presnap, 0); } } default: /* handled at entry */ return; - } } @@ -3008,15 +3043,17 @@ Editor::setup_toolbar () mouse_mode_size_group->add_widget (mouse_draw_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); - - 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); + if (!Profile->get_mixbus()) { + 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_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); + } else { + mouse_mode_size_group->add_widget (zoom_preset_selector); + 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); @@ -3071,8 +3108,7 @@ 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_preset_selector.set_icon (ArdourIcon::ZoomExpand); zoom_in_button.set_name ("zoom button"); zoom_in_button.set_icon (ArdourIcon::ZoomIn); @@ -3104,10 +3140,12 @@ Editor::setup_toolbar () } /* Track zoom buttons */ + _track_box.set_spacing (2); + _track_box.set_border_width (2); + visible_tracks_selector.set_name ("zoom button"); if (Profile->get_mixbus()) { - visible_tracks_selector.set_image(::get_icon ("tav_exp")); - visible_tracks_selector.set_size_request (42, -1); + visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand); } else { set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2); } @@ -3123,14 +3161,14 @@ Editor::setup_toolbar () tav_shrink_button.set_related_action (act); if (ARDOUR::Profile->get_mixbus()) { - _zoom_box.pack_start (visible_tracks_selector); + _track_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); + _track_box.pack_start (tav_shrink_button); + _track_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); + _track_box.pack_start (visible_tracks_selector); + _track_box.pack_start (tav_shrink_button); + _track_box.pack_start (tav_expand_button); } snap_box.set_spacing (2); @@ -3144,7 +3182,13 @@ Editor::setup_toolbar () snap_box.pack_start (snap_mode_selector, false, false); snap_box.pack_start (snap_type_selector, false, false); - snap_box.pack_start (edit_point_selector, false, false); + + /* Edit Point*/ + HBox *ep_box = manage (new HBox); + ep_box->set_spacing (2); + ep_box->set_border_width (2); + + ep_box->pack_start (edit_point_selector, false, false); /* Nudge */ @@ -3162,35 +3206,35 @@ Editor::setup_toolbar () /* Pack everything in... */ - HBox* hbox = manage (new HBox); - hbox->set_spacing(2); - toolbar_hbox.set_spacing (2); - toolbar_hbox.set_border_width (1); + toolbar_hbox.set_border_width (2); toolbar_hbox.pack_start (*mode_box, false, false); + if (!ARDOUR::Profile->get_trx()) { + + toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); + toolbar_hbox.pack_start (_zoom_box, false, false); - toolbar_hbox.pack_start (*hbox, false, false); - } - if (!ARDOUR::Profile->get_trx()) { - hbox->pack_start (snap_box, false, false); - hbox->pack_start (*nudge_box, false, false); - } + toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); + + toolbar_hbox.pack_start (_track_box, false, false); + + toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); + + toolbar_hbox.pack_start (snap_box, false, false); - hbox->show_all (); + toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); - toolbar_base.set_name ("ToolBarBase"); - toolbar_base.add (toolbar_hbox); + toolbar_hbox.pack_start (*ep_box, false, false); - _toolbar_viewport.add (toolbar_base); - /* stick to the required height but allow width to vary if there's not enough room */ - _toolbar_viewport.set_size_request (1, -1); + toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); - toolbar_frame.set_shadow_type (SHADOW_OUT); - toolbar_frame.set_name ("BaseFrame"); - toolbar_frame.add (_toolbar_viewport); + toolbar_hbox.pack_start (*nudge_box, false, false); + } + + toolbar_hbox.show_all (); } void @@ -3792,7 +3836,7 @@ Editor::build_track_count_menu () 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))); + zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal))); } } @@ -3929,85 +3973,6 @@ Editor::cycle_zoom_focus () } } -void -Editor::pane_allocation_handler (Allocation &alloc, Paned* which) -{ - /* recover or initialize pane positions. do this here rather than earlier because - we don't want the positions to change the child allocations, which they seem to do. - - See comments in mixer_ui.cc about how this works. - */ - - float pos; - XMLProperty* prop; - XMLNode* geometry = ARDOUR_UI::instance()->editor_settings(); - - enum Pane { - Horizontal = 0x1, - Vertical = 0x2 - }; - - static Pane done; - - if (which == static_cast (&edit_pane)) { - - if (done & Horizontal) { - return; - } - - if (geometry && (prop = geometry->property ("notebook-shrunk"))) { - _notebook_shrunk = string_is_affirmative (prop->value ()); - } - - if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) { - /* initial allocation is 90% to canvas, 10% to notebook */ - pos = (int) floor (alloc.get_width() * 0.90f); - } else { - pos = atof (prop->value()); - } - - if (pos > 1.0f) { - /* older versions of Ardour stored absolute position */ - if (alloc.get_width() > pos) { - edit_pane.set_position (pos); - done = (Pane) (done | Horizontal); - } - } else { - if (alloc.get_width() > 1.0/pos) { - paned_set_position_as_fraction (edit_pane, pos, false); - done = (Pane) (done | Horizontal); - } - } - - } else if (which == static_cast (&editor_summary_pane)) { - - if (done & Vertical) { - return; - } - - if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) { - /* initial allocation is 90% to canvas, 10% to summary */ - pos = (int) floor (alloc.get_height() * 0.90f); - } else { - - pos = atof (prop->value()); - } - - if (pos > 1.0f) { - /* older versions of Ardour stored absolute position */ - if (alloc.get_height() > pos) { - editor_summary_pane.set_position (pos); - done = (Pane) (done | Vertical); - } - } else { - if (alloc.get_height() > 1.0/pos) { - paned_set_position_as_fraction (editor_summary_pane, pos, true); - done = (Pane) (done | Vertical); - } - } - } -} - void Editor::set_show_measures (bool yn) { @@ -4094,9 +4059,9 @@ Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t durat framecnt_t offset = paste_count * duration; /* snap offset so pos + offset is aligned to the grid */ - framepos_t offset_pos = pos + offset; + MusicFrame offset_pos (pos + offset, 0); snap_to(offset_pos, RoundUpMaybe); - offset = offset_pos - pos; + offset = offset_pos.frame - pos; return offset; } @@ -4127,6 +4092,47 @@ Editor::get_grid_beat_divisions(framepos_t position) return 0; } +/** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent. + if the grid is non-musical, returns 0. + if the grid is snapped to bars, returns -1. + @param event_state the current keyboard modifier mask. +*/ +int32_t +Editor::get_grid_music_divisions (uint32_t event_state) +{ + if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) { + return 0; + } + + if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) { + return 0; + } + + switch (_snap_type) { + case SnapToBeatDiv128: return 128; + case SnapToBeatDiv64: return 64; + case SnapToBeatDiv32: return 32; + case SnapToBeatDiv28: return 28; + case SnapToBeatDiv24: return 24; + case SnapToBeatDiv20: return 20; + case SnapToBeatDiv16: return 16; + case SnapToBeatDiv14: return 14; + case SnapToBeatDiv12: return 12; + case SnapToBeatDiv10: return 10; + case SnapToBeatDiv8: return 8; + case SnapToBeatDiv7: return 7; + case SnapToBeatDiv6: return 6; + case SnapToBeatDiv5: return 5; + case SnapToBeatDiv4: return 4; + case SnapToBeatDiv3: return 3; + case SnapToBeatDiv2: return 2; + case SnapToBeat: return 1; + case SnapToBar : return -1; + default: return 0; + } + return 0; +} + Evoral::Beats Editor::get_grid_type_as_beats (bool& success, framepos_t position) { @@ -4139,10 +4145,11 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position) switch (_snap_type) { case SnapToBeat: - return Evoral::Beats(1.0); + return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor()); case SnapToBar: if (_session) { - return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar()); + const Meter& m = _session->tempo_map().meter_at_frame (position); + return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor()); } break; default: @@ -4327,7 +4334,7 @@ Editor::new_playlists (TimeAxisView* v) begin_reversible_command (_("new playlists")); vector > playlists; _session->playlists->get (playlists); - mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id); commit_reversible_command (); } @@ -4343,7 +4350,7 @@ Editor::copy_playlists (TimeAxisView* v) begin_reversible_command (_("copy playlists")); vector > playlists; _session->playlists->get (playlists); - mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id); commit_reversible_command (); } @@ -4358,20 +4365,20 @@ Editor::clear_playlists (TimeAxisView* v) 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); + mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id); commit_reversible_command (); } void Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector > const & playlists) { - atv.use_new_playlist (sz > 1 ? false : true, playlists); + atv.use_new_playlist (sz > 1 ? false : true, playlists, false); } void Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector > const & playlists) { - atv.use_copy_playlist (sz > 1 ? false : true, playlists); + atv.use_new_playlist (sz > 1 ? false : true, playlists, true); } void @@ -4448,7 +4455,7 @@ Editor::current_visual_state (bool with_tracks) vs->zoom_focus = zoom_focus; if (with_tracks) { - *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state; + vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state()); } return vs; @@ -4513,7 +4520,7 @@ Editor::use_visual_state (VisualState& vs) reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel); if (vs.gui_state) { - *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state; + ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state()); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (*i)->clear_property_cache(); @@ -4581,6 +4588,12 @@ Editor::set_samples_per_pixel (framecnt_t spp) instant_save (); } +framepos_t +Editor::playhead_cursor_sample () const +{ + return playhead_cursor->current_frame(); +} + void Editor::queue_visual_videotimeline_update () { @@ -4647,10 +4660,8 @@ Editor::visual_changer (const VisualChange& vc) compute_fixed_ruler_scale (); - std::vector grid; - compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples()); - compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples()); - update_tempo_based_rulers (grid); + compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples()); + update_tempo_based_rulers (); update_video_timeline(); } @@ -4696,14 +4707,16 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_ framepos_t where = 0; EditPoint ep = _edit_point; - if (Profile->get_mixbus()) - if (ep == EditAtSelectedMarker) + if (Profile->get_mixbus()) { + if (ep == EditAtSelectedMarker) { ep = EditAtPlayhead; + } + } if (from_outside_canvas && (ep == EditAtMouse)) { ep = EditAtPlayhead; } else if (from_context_menu && (ep == EditAtMouse)) { - return canvas_event_sample (&context_click_event, 0, 0); + return canvas_event_sample (&context_click_event, 0, 0); } if (entered_marker) { @@ -4719,6 +4732,8 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_ ep = EditAtPlayhead; } + MusicFrame snap_mf (0, 0); + switch (ep) { case EditAtPlayhead: if (_dragging_playhead) { @@ -4751,7 +4766,9 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_ /* XXX not right but what can we do ? */ return 0; } - snap_to (where); + snap_mf.frame = where; + snap_to (snap_mf); + where = snap_mf.frame; DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where)); break; } @@ -4769,7 +4786,7 @@ Editor::set_loop_range (framepos_t start, framepos_t end, string cmd) Location* tll; if ((tll = transport_loop_location()) == 0) { - Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop); + Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0)); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4796,7 +4813,7 @@ Editor::set_punch_range (framepos_t start, framepos_t end, string cmd) Location* tpl; if ((tpl = transport_punch_location()) == 0) { - Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch); + Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0)); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_punch_location (loc); @@ -4901,7 +4918,7 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie */ RegionSelection -Editor::get_regions_from_selection_and_edit_point () +Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas) { RegionSelection regions; @@ -4918,7 +4935,7 @@ Editor::get_regions_from_selection_and_edit_point () /* no region selected or entered, but some selected tracks: * act on all regions on the selected tracks at the edit point */ - framepos_t const where = get_preferred_edit_position (); + framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas); get_regions_at(regions, where, tracks); } } @@ -5060,6 +5077,38 @@ Editor::get_regions_corresponding_to (boost::shared_ptr region, vector region) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* tatv; + if ((tatv = dynamic_cast (*i)) != 0) { + if (!tatv->track()) { + continue; + } + RegionView* marv = tatv->view()->find_view (region); + if (marv) { + return marv; + } + } + } + return NULL; +} + +RouteTimeAxisView* +Editor::rtav_from_route (boost::shared_ptr route) const +{ + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { + RouteTimeAxisView* rtav; + if ((rtav = dynamic_cast (*i)) != 0) { + if (rtav->route() == route) { + return rtav; + } + } + } + return NULL; +} + void Editor::show_rhythm_ferret () { @@ -5084,7 +5133,7 @@ Editor::first_idle () true ); dialog->present (); - ARDOUR_UI::instance()->flush_pending (); + ARDOUR_UI::instance()->flush_pending (60); } for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { @@ -5201,7 +5250,7 @@ Editor::region_view_added (RegionView * rv) MidiRegionView* mrv = dynamic_cast (rv); if (mrv) { - list > > > >::iterator rnote; + list > >::iterator rnote; for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) { if (rv->region()->id () == (*rnote).first) { mrv->select_notes ((*rnote).second); @@ -5220,16 +5269,13 @@ Editor::region_view_removed () _summary->set_background_dirty (); } -RouteTimeAxisView* -Editor::axis_view_from_route (boost::shared_ptr r) const +TimeAxisView* +Editor::axis_view_from_stripable (boost::shared_ptr s) const { - TrackViewList::const_iterator j = track_views.begin (); - while (j != track_views.end()) { - RouteTimeAxisView* rtv = dynamic_cast (*j); - if (rtv && rtv->route() == r) { - return rtv; + for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) { + if ((*j)->stripable() == s) { + return *j; } - ++j; } return 0; @@ -5242,7 +5288,7 @@ Editor::axis_views_from_routes (boost::shared_ptr r) const TrackViewList t; for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { - TimeAxisView* tv = axis_view_from_route (*i); + TimeAxisView* tv = axis_view_from_stripable (*i); if (tv) { t.push_back (tv); } @@ -5269,73 +5315,94 @@ Editor::resume_route_redisplay () } void -Editor::add_vcas (VCAList& vcas) +Editor::add_vcas (VCAList& vlist) { - VCATimeAxisView* vtv; - list new_views; + StripableList sl; - for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) { - vtv = new VCATimeAxisView (*this, _session, *_track_canvas); - vtv->set_vca (*v); - new_views.push_back (vtv); + for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) { + sl.push_back (boost::dynamic_pointer_cast (*v)); } - if (new_views.size() > 0) { - _routes->vcas_added (new_views); - } + add_stripables (sl); } void -Editor::add_routes (RouteList& routes) +Editor::add_routes (RouteList& rlist) { - ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes) + StripableList sl; + + for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) { + sl.push_back (*r); + } - RouteTimeAxisView *rtv; - list new_views; + add_stripables (sl); +} + +void +Editor::add_stripables (StripableList& sl) +{ + list new_views; + boost::shared_ptr v; + boost::shared_ptr r; TrackViewList new_selection; bool from_scratch = (track_views.size() == 0); - for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { - boost::shared_ptr route = (*x); + sl.sort (StripablePresentationInfoSorter()); - if (route->is_auditioner() || route->is_monitor()) { - continue; - } + for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) { - DataType dt = route->input()->default_type(); + if ((v = boost::dynamic_pointer_cast (*s)) != 0) { - if (dt == ARDOUR::DataType::AUDIO) { - rtv = new AudioTimeAxisView (*this, _session, *_track_canvas); - rtv->set_route (route); - } else if (dt == ARDOUR::DataType::MIDI) { - rtv = new MidiTimeAxisView (*this, _session, *_track_canvas); - rtv->set_route (route); - } else { - throw unknown_type(); - } + VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas); + vtv->set_vca (v); + new_views.push_back (vtv); + + } else if ((r = boost::dynamic_pointer_cast (*s)) != 0) { + + if (r->is_auditioner() || r->is_monitor()) { + continue; + } - new_views.push_back (rtv); - track_views.push_back (rtv); - new_selection.push_back (rtv); + RouteTimeAxisView* rtv; + DataType dt = r->input()->default_type(); - rtv->effective_gain_display (); + if (dt == ARDOUR::DataType::AUDIO) { + rtv = new AudioTimeAxisView (*this, _session, *_track_canvas); + rtv->set_route (r); + } else if (dt == ARDOUR::DataType::MIDI) { + rtv = new MidiTimeAxisView (*this, _session, *_track_canvas); + rtv->set_route (r); + } else { + throw unknown_type(); + } + + new_views.push_back (rtv); + track_views.push_back (rtv); + new_selection.push_back (rtv); + + rtv->effective_gain_display (); - rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); - rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed)); + rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); + rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed)); + } } if (new_views.size() > 0) { - _routes->routes_added (new_views); - _summary->routes_added (new_views); + _routes->time_axis_views_added (new_views); + //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */ } - if (!from_scratch) { + /* note: !new_selection.empty() means that we got some routes rather + * than just VCAs + */ + + if (!from_scratch && !new_selection.empty()) { selection->tracks.clear(); selection->add (new_selection); begin_selection_op_history(); } - if (show_editor_mixer_when_tracks_arrive) { + if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) { show_editor_mixer (true); } @@ -5395,6 +5462,16 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) next_tv = (*i); } + // skip VCAs (cannot be selected, n/a in editor-mixer) + if (dynamic_cast (next_tv)) { + /* VCAs are sorted last in line -- route_sorter.h, jump to top */ + next_tv = track_views.front(); + } + if (dynamic_cast (next_tv)) { + /* just in case: no master, only a VCA remains */ + next_tv = 0; + } + if (next_tv) { set_selected_mixer_strip (*next_tv); @@ -5411,6 +5488,9 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) void Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection) { + if (!tv) { + return; + } if (apply_to_selection) { for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) { @@ -5433,6 +5513,18 @@ Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection) } } +void +Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view) +{ + if (!tv) { + return; + } + _routes->show_track_in_display (*tv); + if (move_into_view) { + ensure_time_axis_view_is_visible (*tv, false); + } +} + bool Editor::sync_track_view_list_and_routes () { @@ -5818,31 +5910,13 @@ Editor::trigger_script (int i) LuaInstance::instance()-> call_action (i); } -void -Editor::set_script_action_name (int i, const std::string& n) -{ - string const a = string_compose (X_("script-action-%1"), i + 1); - Glib::RefPtr act = ActionManager::get_action(X_("Editor"), a.c_str()); - assert (act); - if (n.empty ()) { - act->set_label (string_compose (_("Unset #%1"), i + 1)); - act->set_tooltip (_("no action bound")); - act->set_sensitive (false); - } else { - act->set_label (n); - act->set_tooltip (n); - act->set_sensitive (true); - } - KeyEditor::UpdateBindings (); -} - void Editor::show_editor_list (bool yn) { if (yn) { - _the_notebook.show (); + _editor_list_vbox.show (); } else { - _the_notebook.hide (); + _editor_list_vbox.hide (); } } @@ -5889,18 +5963,6 @@ Editor::update_region_layering_order_editor () void Editor::setup_fade_images () { - _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear"))); - _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric"))); - _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut"))); - _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut"))); - _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power"))); - - _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); - _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric"))); - _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); - _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); - _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power"))); - _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear"))); _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric"))); _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut"))); @@ -5950,16 +6012,16 @@ Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page) if (_notebook_shrunk) { if (pre_notebook_shrink_pane_width) { - edit_pane.set_position (*pre_notebook_shrink_pane_width); + edit_pane.set_divider (0, *pre_notebook_shrink_pane_width); } _notebook_shrunk = false; } else { - pre_notebook_shrink_pane_width = edit_pane.get_position(); + pre_notebook_shrink_pane_width = edit_pane.get_divider(); /* this expands the LHS of the edit pane to cover the notebook PAGE but leaves the tabs visible. */ - edit_pane.set_position (edit_pane.get_position() + page->get_width()); + edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width()); _notebook_shrunk = true; } } @@ -6056,6 +6118,9 @@ Editor::ui_parameter_changed (string parameter) } _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set()); _cursor_stack.push_back(_cursors->grabber); + edit_pane.set_drag_cursor (*_cursors->expand_left_right); + editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down); + } else if (parameter == "draggable-playhead") { if (_verbose_cursor) { playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());