X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=58f66fcd8a69870fe6107edd4984ce8655537dfd;hb=86244875a40206694c142af8fe1128f28293c467;hp=74006c66f15d938b0868e9fb073a91e5ff17a91c;hpb=6a634b9c72b0118efc2dd73a56836365b7517b01;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 74006c66f1..58f66fcd8a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -114,6 +114,8 @@ #include "editor_regions.h" #include "editor_locations.h" #include "editor_snapshots.h" +#include "editor_summary.h" +#include "region_layering_order_editor.h" #include "i18n.h" @@ -147,6 +149,7 @@ static const gchar *_snap_type_strings[] = { N_("Beats/32"), N_("Beats/28"), N_("Beats/24"), + N_("Beats/20"), N_("Beats/16"), N_("Beats/14"), N_("Beats/12"), @@ -200,6 +203,7 @@ static const gchar *_rb_opt_strings[] = { N_("Unpitched percussion with stable notes"), N_("Crisp monophonic instrumental"), N_("Unpitched solo percussion"), + N_("Resample without preserving pitch"), 0 }; #endif @@ -214,6 +218,7 @@ Gdk::Cursor* Editor::right_side_trim_cursor = 0; Gdk::Cursor* Editor::fade_in_cursor = 0; Gdk::Cursor* Editor::fade_out_cursor = 0; Gdk::Cursor* Editor::grabber_cursor = 0; +Gdk::Cursor* Editor::grabber_note_cursor = 0; Gdk::Cursor* Editor::grabber_edit_point_cursor = 0; Gdk::Cursor* Editor::zoom_cursor = 0; Gdk::Cursor* Editor::time_fx_cursor = 0; @@ -226,6 +231,7 @@ Gdk::Cursor* Editor::midi_erase_cursor = 0; Gdk::Cursor* Editor::wait_cursor = 0; Gdk::Cursor* Editor::timebar_cursor = 0; Gdk::Cursor* Editor::transparent_cursor = 0; +Gdk::Cursor* Editor::up_down_cursor = 0; void show_me_the_size (Requisition* r, const char* what) @@ -297,7 +303,7 @@ Editor::Editor () , meters_running(false) , _pending_locate_request (false) , _pending_initial_locate (false) - + , _last_cut_copy_source_track (0) { constructed = false; @@ -327,6 +333,7 @@ Editor::Editor () edit_point_strings = I18N (_edit_point_strings); #ifdef USE_RUBBERBAND rb_opt_strings = I18N (_rb_opt_strings); + rb_current_opt = 4; #endif snap_threshold = 5.0; @@ -346,7 +353,6 @@ Editor::Editor () show_gain_after_trim = false; verbose_cursor_on = true; last_item_entered = 0; - last_item_entered_n = 0; have_pending_keyboard_selection = false; _follow_playhead = true; @@ -379,11 +385,8 @@ Editor::Editor () _dragging_edit_point = false; select_new_marker = false; rhythm_ferret = 0; + layering_order_editor = 0; _bundle_manager = 0; - for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { - _global_port_matrix[*i] = 0; - } - allow_vertical_scroll = false; no_save_visual = false; resize_idle_id = -1; @@ -534,7 +537,6 @@ Editor::Editor () edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); - edit_packer.attach (zoom_vbox, 0, 1, 0, 2, SHRINK, FILL, 0, 0); /* labels for the rulers */ edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0); /* labels for the marker "tracks" */ @@ -665,9 +667,6 @@ Editor::Editor () set_mouse_mode (MouseObject, true); set_edit_point_preference (EditAtMouse, true); - XMLNode* node = ARDOUR_UI::instance()->editor_settings(); - set_state (*node, Stateful::loading_state_version); - _playlist_selector = new PlaylistSelector(); _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast (_playlist_selector))); @@ -708,7 +707,7 @@ Editor::Editor () WindowTitle title(Glib::get_application_name()); title += _("Editor"); set_title (title.get_string()); - set_wmclass (X_("ardour_editor"), "Ardour"); + set_wmclass (X_("ardour_editor"), PROGRAM_NAME); add (vpacker); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); @@ -751,7 +750,7 @@ Editor::~Editor() image_socket_listener = 0 ; } #endif - + delete _routes; delete _route_groups; delete track_canvas; @@ -797,7 +796,7 @@ Editor::set_entered_regionview (RegionView* rv) } if ((entered_regionview = rv) != 0) { - entered_regionview->entered (); + entered_regionview->entered (internal_editing ()); } } @@ -837,8 +836,6 @@ Editor::show_window () tv = (static_cast(*i)); tv->reset_height (); } - - reset_zoom (frames_per_unit); } present (); @@ -979,11 +976,14 @@ Editor::map_position_change (nframes64_t frame) { ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame) - if (_session == 0 || !_follow_playhead) { + if (_session == 0) { return; } - center_screen (frame); + if (_follow_playhead) { + center_screen (frame); + } + playhead_cursor->set_position (frame); } @@ -1093,6 +1093,7 @@ Editor::set_session (Session *t) but use Gtkmm2ext::UI::instance()->call_slot(); */ + _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context()); _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context()); _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context()); _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context()); @@ -1125,7 +1126,7 @@ Editor::set_session (Session *t) Location* loc = _session->locations()->auto_loop_location(); if (loc == 0) { - loc = new Location (0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); + loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } @@ -1138,7 +1139,7 @@ Editor::set_session (Session *t) loc = _session->locations()->auto_punch_location(); if (loc == 0) { - loc = new Location (0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); + loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } @@ -1237,6 +1238,11 @@ Editor::build_cursors () grabber_cursor = new Gdk::Cursor (HAND2); + { + Glib::RefPtr grabber_note_pixbuf (::get_icon ("grabber_note")); + grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10); + } + { Glib::RefPtr grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point")); grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17); @@ -1273,6 +1279,7 @@ Editor::build_cursors () midi_select_cursor = new Gdk::Cursor (CENTER_PTR); midi_resize_cursor = new Gdk::Cursor (SIZING); midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX); + up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW); } /** Pop up a context menu for when the user clicks on a fade in or fade out */ @@ -1499,28 +1506,42 @@ Editor::build_track_region_context_menu (nframes64_t frame) MenuList& edit_items = track_region_context_menu.items(); edit_items.clear(); + /* we've just cleared the track region context menu, so the menu that these + two items were on will have disappeared; stop them dangling. + */ + region_edit_menu_split_item = 0; + region_edit_menu_split_multichannel_item = 0; + RouteTimeAxisView* rtv = dynamic_cast (clicked_axisview); if (rtv) { boost::shared_ptr tr; boost::shared_ptr pl; - if ((tr = rtv->track()) && ((pl = tr->playlist()))) { - Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * tr->speed())); + /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this + mode and so offering region context is somewhat confusing. + */ + if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) { + framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed()); + uint32_t regions_at = pl->count_regions_at (framepos); + list > regions_for_menu; if (selection->regions.size() > 1) { // there's already a multiple selection: just add a // single region context menu that will act on all // selected regions - boost::shared_ptr dummy_region; // = NULL - add_region_context_items (rtv->view(), dummy_region, edit_items); - } else { - for (Playlist::RegionList::reverse_iterator i = regions->rbegin(); i != regions->rend(); ++i) { - add_region_context_items (rtv->view(), (*i), edit_items); - } - } - delete regions; + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + regions_for_menu.push_back ((*i)->region ()); + } + } else { + boost::shared_ptr top_region = pl->top_region_at (framepos); + if (top_region) { + regions_for_menu.push_back (top_region); + } + } + + add_region_context_items (rtv->view(), regions_for_menu, edit_items, framepos, regions_at > 1); } } @@ -1545,7 +1566,6 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast (pl)) != 0)) { - Playlist::RegionList* regions = pl->regions_at (frame); AudioPlaylist::Crossfades xfades; apl->crossfades_at (frame, xfades); @@ -1556,18 +1576,26 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } + framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed()); + uint32_t regions_at = pl->count_regions_at (framepos); + list > regions_for_menu; + if (selection->regions.size() > 1) { - // there's already a multiple selection: just add a - // single region context menu that will act on all - // selected regions - boost::shared_ptr dummy_region; // = NULL - add_region_context_items (atv->audio_view(), dummy_region, edit_items); - } else { - for (Playlist::RegionList::reverse_iterator i = regions->rbegin(); i != regions->rend(); ++i) { - add_region_context_items (atv->audio_view(), (*i), edit_items); + // there's already a multiple selection: just add a + // single region context menu that will act on all + // selected regions + + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + regions_for_menu.push_back ((*i)->region ()); } - } - delete regions; + } else { + boost::shared_ptr top_region = pl->top_region_at (framepos); + if (top_region) { + regions_for_menu.push_back (top_region); + } + } + + add_region_context_items (atv->audio_view(), regions_for_menu, edit_items, framepos, regions_at > 1); } } @@ -1645,7 +1673,7 @@ Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_pt } items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr (xfade)))); - items.push_back (MenuElem (_("Edit"), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); + items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); if (xfade->can_follow_overlap()) { @@ -1687,7 +1715,8 @@ Editor::xfade_edit_right_region () } void -Editor::add_region_context_items (StreamView* sv, boost::shared_ptr region, Menu_Helpers::MenuList& edit_items) +Editor::add_region_context_items (StreamView* sv, list > regions, Menu_Helpers::MenuList& edit_items, + framepos_t position, bool multiple_regions_at_position) { using namespace Menu_Helpers; Gtk::MenuItem* foo_item; @@ -1695,24 +1724,100 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi MenuList& items = region_menu->items(); region_menu->set_name ("ArdourContextMenu"); - boost::shared_ptr ar; - boost::shared_ptr mr; + /* Look through the regions that we are handling and make notes about what we have got */ + + bool have_audio = false; + bool have_midi = false; + bool have_locked = false; + bool have_unlocked = false; + bool have_position_lock_style_audio = false; + bool have_position_lock_style_music = false; + bool have_muted = false; + bool have_unmuted = false; + bool have_opaque = false; + bool have_non_opaque = false; + bool have_not_at_natural_position = false; + bool have_envelope_visible = false; + bool have_envelope_invisible = false; + bool have_envelope_active = false; + bool have_envelope_inactive = false; + bool have_non_unity_scale_amplitude = false; + + for (list >::const_iterator i = regions.begin(); i != regions.end(); ++i) { + boost::shared_ptr ar = boost::dynamic_pointer_cast (*i); + if (ar) { + have_audio = true; + } + if (boost::dynamic_pointer_cast (*i)) { + have_midi = true; + } + + if ((*i)->locked()) { + have_locked = true; + } else { + have_unlocked = true; + } + + if ((*i)->position_lock_style() == MusicTime) { + have_position_lock_style_music = true; + } else { + have_position_lock_style_audio = true; + } - if (region) { - ar = boost::dynamic_pointer_cast (region); - mr = boost::dynamic_pointer_cast (region); + if ((*i)->muted()) { + have_muted = true; + } else { + have_unmuted = true; + } + + if ((*i)->opaque()) { + have_opaque = true; + } else { + have_non_opaque = true; + } + + if (!(*i)->at_natural_position()) { + have_not_at_natural_position = true; + } + + if (ar) { + RegionView* rv = sv->find_view (ar); + AudioRegionView* arv = dynamic_cast (rv); + + if (rv && arv && arv->envelope_visible()) { + have_envelope_visible = true; + } else { + have_envelope_invisible = true; + } + + if (ar->envelope_active()) { + have_envelope_active = true; + } else { + have_envelope_inactive = true; + } + + if (ar->scale_amplitude() != 1) { + have_non_unity_scale_amplitude = true; + } + } + } + + if (regions.size() == 1) { /* when this particular menu pops up, make the relevant region become selected. */ region_menu->signal_map_event().connect ( - sigc::bind (sigc::mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); + sigc::bind (sigc::mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr (regions.front())) + ); items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &Editor::rename_region))); - if (mr) { + + if (have_midi) { items.push_back (MenuElem (_("List Editor..."), sigc::mem_fun(*this, &Editor::show_midi_list_editor))); } + items.push_back (MenuElem (_("Region Properties..."), sigc::mem_fun(*this, &Editor::edit_region))); } @@ -1730,107 +1835,96 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (MenuElem (_("Export..."), sigc::mem_fun(*this, &Editor::export_region))); items.push_back (MenuElem (_("Bounce"), sigc::mem_fun(*this, &Editor::bounce_region_selection))); - if (ar) { + if (have_audio) { items.push_back (MenuElem (_("Spectral Analysis..."), sigc::mem_fun(*this, &Editor::analyze_region_selection))); } items.push_back (SeparatorElem()); - sigc::connection fooc; - boost::shared_ptr region_to_check; - - if (region) { - region_to_check = region; - } else { - region_to_check = selection->regions.front()->region(); - } - items.push_back (CheckMenuElem (_("Lock"))); CheckMenuItem* region_lock_item = static_cast(&items.back()); - if (region_to_check->locked()) { + if (have_locked && !have_unlocked) { region_lock_item->set_active(); + } else if (have_locked && have_unlocked) { + region_lock_item->set_inconsistent (); } region_lock_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_lock)); items.push_back (CheckMenuElem (_("Glue to Bars and Beats"))); CheckMenuItem* bbt_glue_item = static_cast(&items.back()); - switch (region_to_check->positional_lock_style()) { - case Region::MusicTime: - bbt_glue_item->set_active (true); - break; - default: - bbt_glue_item->set_active (false); - break; + if (have_position_lock_style_music && !have_position_lock_style_audio) { + bbt_glue_item->set_active (); + } else if (have_position_lock_style_music && have_position_lock_style_audio) { + bbt_glue_item->set_inconsistent (); } bbt_glue_item->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_region_lock_style)); items.push_back (CheckMenuElem (_("Mute"))); CheckMenuItem* region_mute_item = static_cast(&items.back()); - fooc = region_mute_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_mute)); - if (region_to_check->muted()) { - fooc.block (true); + + if (have_muted && !have_unmuted) { region_mute_item->set_active(); - fooc.block (false); + } else if (have_muted && have_unmuted) { + region_mute_item->set_inconsistent (); } + region_mute_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_mute)); + items.push_back (MenuElem (_("Transpose..."), mem_fun(*this, &Editor::pitch_shift_regions))); if (!Profile->get_sae()) { items.push_back (CheckMenuElem (_("Opaque"))); CheckMenuItem* region_opaque_item = static_cast(&items.back()); - fooc = region_opaque_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_opaque)); - if (region_to_check->opaque()) { - fooc.block (true); + if (have_opaque && !have_non_opaque) { region_opaque_item->set_active(); - fooc.block (false); + } else if (have_opaque && have_non_opaque) { + region_opaque_item->set_inconsistent (); } + region_opaque_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_opaque)); } items.push_back (CheckMenuElem (_("Original Position"), sigc::mem_fun(*this, &Editor::naturalize))); - if (region_to_check->at_natural_position()) { + if (!have_not_at_natural_position) { items.back().set_sensitive (false); } items.push_back (SeparatorElem()); - if (ar) { - - RegionView* rv = sv->find_view (ar); - AudioRegionView* arv = dynamic_cast(rv); + if (have_audio) { if (!Profile->get_sae()) { items.push_back (MenuElem (_("Reset Envelope"), sigc::mem_fun(*this, &Editor::reset_region_gain_envelopes))); items.push_back (CheckMenuElem (_("Envelope Visible"))); CheckMenuItem* region_envelope_visible_item = static_cast (&items.back()); - fooc = region_envelope_visible_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); - if (arv->envelope_visible()) { - fooc.block (true); - region_envelope_visible_item->set_active (true); - fooc.block (false); + if (have_envelope_visible && !have_envelope_invisible) { + region_envelope_visible_item->set_active (); + } else if (have_envelope_visible && have_envelope_invisible) { + region_envelope_visible_item->set_inconsistent (); } + region_envelope_visible_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); items.push_back (CheckMenuElem (_("Envelope Active"))); CheckMenuItem* region_envelope_active_item = static_cast (&items.back()); - fooc = region_envelope_active_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_active)); - if (ar->envelope_active()) { - fooc.block (true); - region_envelope_active_item->set_active (true); - fooc.block (false); + if (have_envelope_active && !have_envelope_inactive) { + region_envelope_active_item->set_active (); + } else if (have_envelope_active && have_envelope_inactive) { + region_envelope_active_item->set_inconsistent (); } + region_envelope_active_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_active)); items.push_back (SeparatorElem()); } items.push_back (MenuElem (_("Normalize..."), sigc::mem_fun(*this, &Editor::normalize_region))); - if (ar->scale_amplitude() != 1) { + if (have_non_unity_scale_amplitude) { items.push_back (MenuElem (_("Reset Gain"), sigc::mem_fun(*this, &Editor::reset_region_scale_amplitude))); } - } else if (mr) { + } else if (have_midi) { items.push_back (MenuElem (_("Quantize"), sigc::mem_fun(*this, &Editor::quantize_region))); items.push_back (MenuElem (_("Fork"), sigc::mem_fun(*this, &Editor::fork_region))); items.push_back (SeparatorElem()); @@ -1892,8 +1986,10 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi region_edit_menu_split_item->set_sensitive (false); } - items.push_back (MenuElem (_("Make Mono Regions"), (sigc::mem_fun(*this, &Editor::split_multichannel_region)))); - region_edit_menu_split_multichannel_item = &items.back(); + if (have_audio) { + items.push_back (MenuElem (_("Make Mono Regions"), (sigc::mem_fun(*this, &Editor::split_multichannel_region)))); + region_edit_menu_split_multichannel_item = &items.back(); + } items.push_back (MenuElem (_("Duplicate"), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)))); items.push_back (MenuElem (_("Multi-Duplicate..."), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), true)))); @@ -1910,7 +2006,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi */ string::size_type pos = 0; - string menu_item_name = (region) ? region->name() : _("Selected Regions"); + string menu_item_name = (regions.size() == 1) ? regions.front()->name() : _("Selected Regions"); while ((pos = menu_item_name.find ("_", pos)) != string::npos) { menu_item_name.replace (pos, 1, "__"); @@ -1918,6 +2014,9 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi } edit_items.push_back (MenuElem (menu_item_name, *region_menu)); + if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) { + edit_items.push_back (MenuElem (_("Choose Top Region..."), (bind (mem_fun(*this, &Editor::change_region_layering_order), position)))); + } edit_items.push_back (SeparatorElem()); } @@ -1942,7 +2041,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) } edit_items.push_back (SeparatorElem()); - edit_items.push_back (MenuElem (_("Silence Range"), sigc::mem_fun(*this, &Editor::separate_region_from_selection))); + edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection))); edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection))); edit_items.push_back (SeparatorElem()); @@ -2142,6 +2241,7 @@ Editor::set_snap_to (SnapType st) case SnapToBeatDiv32: case SnapToBeatDiv28: case SnapToBeatDiv24: + case SnapToBeatDiv20: case SnapToBeatDiv16: case SnapToBeatDiv14: case SnapToBeatDiv12: @@ -2318,6 +2418,8 @@ Editor::set_state (const XMLNode& node, int /*version*/) if ((prop = node.property ("zoom"))) { reset_zoom (PBD::atof (prop->value())); + } else { + reset_zoom (frames_per_unit); } if ((prop = node.property ("snap-to"))) { @@ -2366,7 +2468,7 @@ Editor::set_state (const XMLNode& node, int /*version*/) if ((prop = node.property ("show-measures"))) { bool yn = string_is_affirmative (prop->value()); - _show_measures = !yn; + _show_measures = yn; RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility")); if (act) { RefPtr tact = RefPtr::cast_dynamic(act); @@ -2446,6 +2548,11 @@ Editor::set_state (const XMLNode& node, int /*version*/) the_notebook.set_current_page (atoi (prop->value ())); } + XMLNodeList children = node.children (); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + selection->set_state (**i, Stateful::current_state_version); + } + return 0; } @@ -2532,6 +2639,8 @@ Editor::get_state () snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ()); node->add_property (X_("editor-list-page"), buf); + node->add_child_nocopy (selection->get_state ()); + return *node; } @@ -2706,6 +2815,9 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) case SnapToBeatDiv24: start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction); break; + case SnapToBeatDiv20: + start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction); + break; case SnapToBeatDiv16: start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction); break; @@ -2920,8 +3032,8 @@ Editor::setup_toolbar () /* Zoom */ - zoom_box.set_spacing (1); - zoom_box.set_border_width (0); + _zoom_box.set_spacing (1); + _zoom_box.set_border_width (0); zoom_in_button.set_name ("EditorTimeButton"); zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU)))); @@ -2939,10 +3051,12 @@ Editor::setup_toolbar () set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true); zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done)); - 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_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); + /* Track zoom buttons */ tav_expand_button.set_name ("TrackHeightButton"); tav_expand_button.set_size_request(-1,20); @@ -2954,18 +3068,20 @@ Editor::setup_toolbar () tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink"))))); tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false)); - track_zoom_box.set_spacing (1); - track_zoom_box.set_border_width (0); - - track_zoom_box.pack_start (tav_shrink_button, false, false); - track_zoom_box.pack_start (tav_expand_button, false, false); - - HBox* zbc = manage (new HBox); - zbc->pack_start (zoom_focus_selector, PACK_SHRINK); - zoom_vbox.pack_start (*zbc, PACK_SHRINK); - zoom_vbox.pack_start (zoom_box, PACK_SHRINK); - zoom_vbox.pack_start (track_zoom_box, PACK_SHRINK); - + _zoom_box.pack_start (tav_shrink_button); + _zoom_box.pack_start (tav_expand_button); + + _zoom_tearoff = manage (new TearOff (_zoom_box)); + + _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + snap_box.set_spacing (1); snap_box.set_border_width (2); @@ -3025,6 +3141,7 @@ Editor::setup_toolbar () toolbar_hbox.set_border_width (1); toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false); + toolbar_hbox.pack_start (*_zoom_tearoff, false, false); toolbar_hbox.pack_start (*_tools_tearoff, false, false); hbox->pack_start (snap_box, false, false); @@ -3047,7 +3164,7 @@ Editor::setup_tooltips () ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects")); ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Gain Automation")); ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range")); - ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions")); + 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 (join_object_range_button, _("Select/Move Objects or Ranges")); ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)")); @@ -3065,6 +3182,7 @@ Editor::setup_tooltips () ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point")); ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes")); ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels")); + ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode")); } void @@ -3472,22 +3590,7 @@ Editor::cycle_edit_mode () void Editor::edit_mode_selection_done () { - if (_session == 0) { - return; - } - - string choice = edit_mode_selector.get_active_text(); - EditMode mode = Slide; - - if (choice == _("Splice Edit")) { - mode = Splice; - } else if (choice == _("Slide Edit")) { - mode = Slide; - } else if (choice == _("Lock Edit")) { - mode = Lock; - } - - Config->set_edit_mode (mode); + Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ())); } void @@ -3518,6 +3621,8 @@ Editor::snap_type_selection_done () snaptype = SnapToBeatDiv14; } else if (choice == _("Beats/16")) { snaptype = SnapToBeatDiv16; + } else if (choice == _("Beats/20")) { + snaptype = SnapToBeatDiv20; } else if (choice == _("Beats/24")) { snaptype = SnapToBeatDiv24; } else if (choice == _("Beats/28")) { @@ -3919,6 +4024,9 @@ Editor::get_grid_type_as_beats (bool& success, nframes64_t position) case SnapToBeatDiv24: return 1.0/24.0; break; + case SnapToBeatDiv20: + return 1.0/20.0; + break; case SnapToBeatDiv16: return 1.0/16.0; break; @@ -4100,10 +4208,8 @@ Editor::control_layout_scroll (GdkEventScroll* ev) } void -Editor::session_state_saved (string snap_name) +Editor::session_state_saved (string) { - ENSURE_GUI_THREAD (*this, &Editor::session_state_saved, snap_name); - update_title (); _snapshots->redisplay (); } @@ -4113,6 +4219,7 @@ Editor::maximise_editing_space () { _mouse_mode_tearoff->set_visible (false); _tools_tearoff->set_visible (false); + _zoom_tearoff->set_visible (false); pre_maximal_horizontal_pane_position = edit_pane.get_position (); pre_maximal_vertical_pane_position = editor_summary_pane.get_position (); @@ -4142,6 +4249,12 @@ Editor::maximise_editing_space () } else { editor_summary_pane.set_position (post_maximal_vertical_pane_position); } + + if (Config->get_keep_tearoffs()) { + _mouse_mode_tearoff->set_visible (true); + _tools_tearoff->set_visible (true); + _zoom_tearoff->set_visible (true); + } } void @@ -4161,6 +4274,7 @@ Editor::restore_editing_space () _mouse_mode_tearoff->set_visible (true); _tools_tearoff->set_visible (true); + _zoom_tearoff->set_visible (true); post_maximal_editor_width = this->get_width(); post_maximal_editor_height = this->get_height(); @@ -4579,7 +4693,7 @@ Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd) Location* tll; if ((tll = transport_loop_location()) == 0) { - Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop); + Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4606,7 +4720,7 @@ Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd) Location* tpl; if ((tpl = transport_punch_location()) == 0) { - Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch); + Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4789,16 +4903,6 @@ Editor::show_rhythm_ferret () rhythm_ferret->present (); } -void -Editor::show_global_port_matrix (ARDOUR::DataType t) -{ - if (_global_port_matrix[t] == 0) { - _global_port_matrix[t] = new GlobalPortMatrixWindow (_session, t); - } - - _global_port_matrix[t]->show (); -} - void Editor::first_idle () { @@ -4910,12 +5014,6 @@ Editor::region_view_added (RegionView *) _summary->set_dirty (); } -void -Editor::streamview_height_changed () -{ - _summary->set_dirty (); -} - TimeAxisView* Editor::axis_view_from_route (boost::shared_ptr r) const { @@ -4979,7 +5077,6 @@ Editor::handle_new_route (RouteList& routes) rtv->effective_gain_display (); rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); - rtv->view()->HeightChanged.connect (sigc::mem_fun (*this, &Editor::streamview_height_changed)); } _routes->routes_added (new_views); @@ -5002,14 +5099,22 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) } ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv); - + RouteTimeAxisView* rtav = dynamic_cast (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()) { + entered_track = 0; + } + } + /* remove it from the list of track views */ TrackViewList::iterator i; @@ -5021,7 +5126,6 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) /* update whatever the current mixer strip is displaying, if revelant */ boost::shared_ptr route; - RouteTimeAxisView* rtav = dynamic_cast (tv); if (rtav) { route = rtav->route (); @@ -5084,12 +5188,13 @@ Editor::foreach_time_axis_view (sigc::slot theslot) } } +/** Find a RouteTimeAxisView by the ID of its route */ RouteTimeAxisView* -Editor::get_route_view_by_id (PBD::ID& id) +Editor::get_route_view_by_route_id (PBD::ID& id) const { RouteTimeAxisView* v; - for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { if((v = dynamic_cast(*i)) != 0) { if(v->route()->id() == id) { return v; @@ -5159,6 +5264,16 @@ Editor::show_region_in_region_list () _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region)); } +void +Editor::step_edit_status_change (bool yn) +{ + if (yn) { + start_step_editing (); + } else { + stop_step_editing (); + } +} + void Editor::start_step_editing () { @@ -5451,3 +5566,41 @@ Editor::show_editor_list (bool yn) the_notebook.hide(); } } + +void +Editor::change_region_layering_order (framepos_t position) +{ + if (!clicked_routeview) { + if (layering_order_editor) { + layering_order_editor->hide (); + } + return; + } + + boost::shared_ptr track = boost::dynamic_pointer_cast (clicked_routeview->route()); + + if (!track) { + return; + } + + boost::shared_ptr pl = track->playlist(); + + if (!pl) { + return; + } + + if (layering_order_editor == 0) { + layering_order_editor = new RegionLayeringOrderEditor(*this); + } + + layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position); + layering_order_editor->maybe_present (); +} + +void +Editor::update_region_layering_order_editor (framepos_t frame) +{ + if (layering_order_editor && layering_order_editor->is_visible ()) { + change_region_layering_order (frame); + } +}