diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2006-03-05 19:39:16 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2006-03-05 19:39:16 +0000 |
commit | 5a39bf595c737dbb36666a9e718ac267e9131380 (patch) | |
tree | 12219a08eec7305a135eafff4210a037ff5f8804 | |
parent | caeb564748e7ece1025f55f005fe5591795ec234 (diff) |
export range markers patch (revisited), change selection model, copy-drag tempo+meter marker patch
git-svn-id: svn://localhost/trunk/ardour2@349 d708f5d6-7413-0410-9779-e7cbd77b26cf
40 files changed, 986 insertions, 435 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index 8ea3f27d81..c0fa90c4d5 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -61,7 +61,6 @@ about.cc actions.cc add_route_dialog.cc ardour_dialog.cc -ardour_message.cc ardour_ui.cc ardour_ui2.cc ardour_ui_dependents.cc @@ -113,6 +112,9 @@ editor_selection_list.cc editor_tempodisplay.cc editor_timefx.cc export_dialog.cc +export_session_dialog.cc +export_region_dialog.cc +export_range_markers_dialog.cc gain_automation_time_axis.cc gain_meter.cc ghostregion.cc diff --git a/gtk2_ardour/actions.cc b/gtk2_ardour/actions.cc index 9f8c95ce2c..1ca9278baf 100644 --- a/gtk2_ardour/actions.cc +++ b/gtk2_ardour/actions.cc @@ -42,9 +42,14 @@ using namespace sigc; vector<RefPtr<Gtk::Action> > ActionManager::session_sensitive_actions; vector<RefPtr<Gtk::Action> > ActionManager::region_list_selection_sensitive_actions; +vector<RefPtr<Gtk::Action> > ActionManager::plugin_selection_sensitive_actions; vector<RefPtr<Gtk::Action> > ActionManager::region_selection_sensitive_actions; vector<RefPtr<Gtk::Action> > ActionManager::track_selection_sensitive_actions; -vector<RefPtr<Gtk::Action> > ActionManager::plugin_selection_sensitive_actions; +vector<RefPtr<Gtk::Action> > ActionManager::point_selection_sensitive_actions; +vector<RefPtr<Gtk::Action> > ActionManager::time_selection_sensitive_actions; +vector<RefPtr<Gtk::Action> > ActionManager::line_selection_sensitive_actions; +vector<RefPtr<Gtk::Action> > ActionManager::playlist_selection_sensitive_actions; + vector<RefPtr<Gtk::Action> > ActionManager::range_sensitive_actions; vector<RefPtr<Gtk::Action> > ActionManager::jack_sensitive_actions; vector<RefPtr<Gtk::Action> > ActionManager::jack_opposite_sensitive_actions; diff --git a/gtk2_ardour/actions.h b/gtk2_ardour/actions.h index b842693eba..330caff1c2 100644 --- a/gtk2_ardour/actions.h +++ b/gtk2_ardour/actions.h @@ -22,9 +22,15 @@ class ActionManager static std::vector<Glib::RefPtr<Gtk::Action> > session_sensitive_actions; static std::vector<Glib::RefPtr<Gtk::Action> > region_list_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > plugin_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > region_selection_sensitive_actions; static std::vector<Glib::RefPtr<Gtk::Action> > track_selection_sensitive_actions; - static std::vector<Glib::RefPtr<Gtk::Action> > plugin_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > point_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > time_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > line_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > playlist_selection_sensitive_actions; + static std::vector<Glib::RefPtr<Gtk::Action> > range_sensitive_actions; static std::vector<Glib::RefPtr<Gtk::Action> > transport_sensitive_actions; static std::vector<Glib::RefPtr<Gtk::Action> > jack_sensitive_actions; diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus index 1e5ce5edfd..372b4fcee2 100644 --- a/gtk2_ardour/ardour.menus +++ b/gtk2_ardour/ardour.menus @@ -15,7 +15,8 @@ <separator/> <menu name='Export' action='Export'> <menuitem action='ExportSession'/> - <menuitem action='ExportRange'/> + <menuitem action='ExportSelection'/> + <menuitem action='ExportRangeMarkers'/> </menu> <separator/> <menu name='Cleanup' action='Cleanup'> diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 752a6f693d..b9f00340db 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -28,6 +28,8 @@ #include <iostream> +#include <gtkmm/messagedialog.h> + #include <pbd/error.h> #include <pbd/compose.h> #include <pbd/basename.h> @@ -58,7 +60,6 @@ #include "actions.h" #include "ardour_ui.h" -#include "ardour_message.h" #include "public_editor.h" #include "audio_clock.h" #include "keyboard.h" @@ -219,7 +220,8 @@ because it has no input connections.\n\ You would be wasting space recording silence."), ds->name()); - ArdourMessage message (editor, X_("cannotrecord"), msg); + MessageDialog message (*editor, msg); + message.run (); } void @@ -402,11 +404,12 @@ ARDOUR_UI::finish() /* use the default name */ if (save_state_canfail ("")) { /* failed - don't quit */ - ArdourMessage (editor, X_("badsave dialog"), + MessageDialog msg (*editor, _("\ Ardour was unable to save your session.\n\n\ If you still wish to quit, please use the\n\n\ \"Just quit\" option.")); + msg.run (); return; } break; @@ -936,11 +939,12 @@ ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t o } catch (...) { - ArdourMessage msg (editor, X_("noport dialog"), + MessageDialog msg (*editor, _("There are insufficient JACK ports available\n\ to create a new track or bus.\n\ You should save Ardour, exit and\n\ restart JACK with more ports.")); + msg.run (); } } @@ -1044,7 +1048,8 @@ ARDOUR_UI::transport_record () case Session::Disabled: if (session->ntracks() == 0) { string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."); - ArdourMessage msg (editor, X_("cannotrecenable"), txt); + MessageDialog msg (*editor, txt); + msg.run (); return; } session->maybe_enable_record (); @@ -1278,12 +1283,13 @@ ARDOUR_UI::engine_halted () update_sample_rate (0); - ArdourMessage msg (editor, X_("halted"), + MessageDialog msg (*editor, _("\ JACK has either been shutdown or it\n\ disconnected Ardour because Ardour\n\ was not fast enough. You can save the\n\ session and/or try to reconnect to JACK .")); + msg.run (); } int32_t @@ -1781,9 +1787,10 @@ ARDOUR_UI::load_session (const string & path, const string & snap_name, string* /* if it already exists, we must have write access */ if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) { - ArdourMessage msg (editor, X_("noaccess dialog"), _("\ + MessageDialog msg (*editor, _("\ You do not have write access to this session.\n\ This prevents the session from being loaded.")); + msg.run (); return -1; } @@ -1901,12 +1908,13 @@ ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* l removed = rep.paths.size(); if (removed == 0) { - ArdourMessage msg (editor, X_("cleanupresults"), + MessageDialog msg (*editor, X_("cleanupresults"), _("\ No audio files were ready for cleanup\n\n\ If this seems suprising, check for any existing\n\ snapshots. These may still include regions that\n\ require some unused files to continue to exist.")); + msg.run (); return; } @@ -2150,8 +2158,9 @@ ARDOUR_UI::halt_on_xrun_message () { ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message)); - ArdourMessage msg (editor, X_("haltonxrun"), + MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up.")); + msg.run (); } void @@ -2173,12 +2182,13 @@ ARDOUR_UI::disk_overrun_handler () if (!have_disk_overrun_displayed) { have_disk_overrun_displayed = true; - ArdourMessage msg (editor, X_("diskrate dialog"), _("\ + MessageDialog msg (*editor, X_("diskrate dialog"), _("\ The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to write data to disk\n\ quickly enough to keep up with recording.\n")); + msg.run (); have_disk_overrun_displayed = false; } } @@ -2190,12 +2200,13 @@ ARDOUR_UI::disk_underrun_handler () if (!have_disk_underrun_displayed) { have_disk_underrun_displayed = true; - ArdourMessage msg (editor, X_("diskrate2 dialog"), + MessageDialog msg (*editor, (_("The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to read data from disk\n\ quickly enough to keep up with playback.\n"))); + msg.run (); have_disk_underrun_displayed = false; } } @@ -2248,8 +2259,8 @@ ARDOUR_UI::disconnect_from_jack () { if (engine) { if( engine->disconnect_from_jack ()) { - ArdourMessage msg (editor, X_("nojack dialog"), - _("Could not disconnect from JACK")); + MessageDialog msg (*editor, _("Could not disconnect from JACK")); + msg.run (); } update_sample_rate (0); @@ -2261,8 +2272,8 @@ ARDOUR_UI::reconnect_to_jack () { if (engine) { if (engine->reconnect_to_jack ()) { - ArdourMessage msg (editor, X_("nojack dialog"), - _("Could not reconnect to JACK")); + MessageDialog msg (*editor, _("Could not reconnect to JACK")); + msg.run (); } update_sample_rate (0); diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index fea1128799..7dc7226c7a 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -587,6 +587,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI LocationUI *location_ui; int create_location_ui (); + void handle_locations_change (ARDOUR::Location*); ColorManager* color_manager; diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 08501e746a..29dc204af9 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -53,6 +53,24 @@ ARDOUR_UI::connect_to_session (Session *s) /* sensitize menu bar options that are now valid */ ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true); + + if (session->locations()->num_range_markers()) { + ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true); + } else { + ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false); + } + + /* there are never any selections on startup */ + + ActionManager::set_sensitive (ActionManager::region_selection_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false); + + session->locations()->added.connect (mem_fun (*this, &ARDOUR_UI::handle_locations_change)); + session->locations()->removed.connect (mem_fun (*this, &ARDOUR_UI::handle_locations_change)); rec_button.set_sensitive (true); shuttle_box.set_sensitive (true); @@ -366,3 +384,14 @@ ARDOUR_UI::toggle_sound_file_browser () } } +void +ARDOUR_UI::handle_locations_change (Location* ignored) +{ + if (session) { + if (session->locations()->num_range_markers()) { + ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true); + } else { + ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false); + } + } +} diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index 5737eba319..bc34adfece 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -110,8 +110,13 @@ ARDOUR_UI::install_actions () act = ActionManager::register_action (main_actions, X_("ExportSession"), _("Export session to audiofile..."), mem_fun (*editor, &PublicEditor::export_session)); ActionManager::session_sensitive_actions.push_back (act); - act = ActionManager::register_action (main_actions, X_("ExportRange"), _("Export range to audiofile..."), mem_fun (*editor, &PublicEditor::export_selection)); + act = ActionManager::register_action (main_actions, X_("ExportSelection"), _("Export selection to audiofile..."), mem_fun (*editor, &PublicEditor::export_selection)); ActionManager::session_sensitive_actions.push_back (act); + ActionManager::time_selection_sensitive_actions.push_back (act); + + act = ActionManager::register_action (main_actions, X_("ExportRangeMarkers"), _("Export range markers to audiofile..."), mem_fun (*editor, &PublicEditor::export_range_markers)); + ActionManager::session_sensitive_actions.push_back (act); + ActionManager::range_sensitive_actions.push_back (act); act = ActionManager::register_action (main_actions, X_("Export"), _("Export")); ActionManager::session_sensitive_actions.push_back (act); @@ -475,4 +480,3 @@ ARDOUR_UI::build_menu_bar () menu_bar_base.set_name ("MainMenuBar"); menu_bar_base.add (menu_hbox); } - diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 0c0c402934..88a0f5eb57 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -832,6 +832,11 @@ AudioTimeAxisView::rename_current_playlist () AudioPlaylist *pl; DiskStream *ds; + /* neither conditions are supposed to be true at this + time, but to leave the design flexible, allow + them to be in the future without causing crashes + */ + if (((ds = get_diskstream()) == 0) ||((pl = ds->playlist()) == 0)) { return; } @@ -853,22 +858,17 @@ AudioTimeAxisView::rename_current_playlist () } void -AudioTimeAxisView::playlist_selected (AudioPlaylist *pl) -{ - DiskStream *ds; - - if ((ds = get_diskstream()) != 0) { - ds->use_playlist (pl); - } -} - -void AudioTimeAxisView::use_copy_playlist () { AudioPlaylist *pl; DiskStream *ds; string name; + /* neither conditions are supposed to be true at this + time, but to leave the design flexible, allow + them to be in the future without causing crashes + */ + if (((ds = get_diskstream()) == 0) || ((pl = ds->playlist()) == 0)) { return; } @@ -902,6 +902,11 @@ AudioTimeAxisView::use_new_playlist () DiskStream *ds; string name; + /* neither conditions are supposed to be true at this + time, but to leave the design flexible, allow + them to be in the future without causing crashes + */ + if (((ds = get_diskstream()) == 0) || ((pl = ds->playlist()) == 0)) { return; } @@ -1003,14 +1008,18 @@ AudioTimeAxisView::selection_click (GdkEventButton* ev) { PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route.edit_group()); - if (Keyboard::modifier_state_contains (ev->state, Keyboard::Shift)) { - if (editor.get_selection().selected (this)) { - editor.get_selection().remove (*tracks); - } else { - editor.get_selection().add (*tracks); - } - } else { + switch (Keyboard::selection_type (ev->state)) { + case Selection::Toggle: + editor.get_selection().toggle (*tracks); + break; + + case Selection::Set: editor.get_selection().set (*tracks); + break; + + case Selection::Extend: + /* not defined yet */ + break; } delete tracks; diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index 19d9f6676c..c481c54ed5 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -227,7 +227,6 @@ class AudioTimeAxisView : public RouteUI, public TimeAxisView void playlist_modified (); void add_playlist_to_playlist_menu (ARDOUR::Playlist*); - void playlist_selected (ARDOUR::AudioPlaylist*); void use_new_playlist (); void use_copy_playlist (); void clear_playlist (); diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 066f29499e..9d788f1566 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1873,8 +1873,8 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false))); + select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); @@ -1958,8 +1958,8 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false))); + select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); @@ -2988,7 +2988,7 @@ Editor::commit_reversible_command () } void -Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove) +Editor::set_selected_track_from_click (Selection::Operation op, bool with_undo, bool no_remove) { if (!clicked_trackview) { return; @@ -2997,25 +2997,29 @@ Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove) if (with_undo) { begin_reversible_command (_("set selected trackview")); } - - if (add) { - + + switch (op) { + case Selection::Toggle: if (selection->selected (clicked_trackview)) { if (!no_remove) { selection->remove (clicked_trackview); } } else { - selection->add (clicked_trackview); + selection->toggle (clicked_trackview); } - - } else { - + break; + case Selection::Set: if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) { /* no commit necessary */ return; } selection->set (clicked_trackview); + break; + + case Selection::Extend: + /* not defined yet */ + break; } if (with_undo) { @@ -3024,7 +3028,7 @@ Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove) } void -Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove) +Editor::set_selected_control_point_from_click (Selection::Operation op, bool with_undo, bool no_remove) { if (!clicked_control_point) { return; @@ -3034,94 +3038,123 @@ Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no begin_reversible_command (_("set selected control point")); } - if (add) { - - } else { - + switch (op) { + case Selection::Set: + break; + case Selection::Toggle: + break; + case Selection::Extend: + break; } - if (with_undo) { commit_reversible_command (); } } void -Editor::set_selected_regionview_from_click (bool add, bool no_track_remove) +Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&> sl) { - if (!clicked_regionview) { - return; - } + set<AudioTimeAxisView*> relevant_tracks; - AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view()); + /* step one: get all selected tracks and all tracks in the relevant edit groups */ - if (!atv) { - return; - } + for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) { - RouteGroup* group = atv->route().edit_group(); - vector<AudioRegionView*> all_equivalent_regions; - - if (group && group->is_active()) { - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view()); - AudioTimeAxisView* tatv; + if (!atv) { + continue; + } - if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { + RouteGroup* group = atv->route().edit_group(); - if (tatv->route().edit_group() != group) { - continue; - } + if (group && group->is_active()) { - AudioPlaylist* pl; - vector<AudioRegion*> results; - AudioRegionView* marv; - DiskStream* ds; - - if ((ds = tatv->get_diskstream()) == 0) { - /* bus */ - continue; - } + /* active group for this track, loop over all tracks and get every member of the group */ + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - if ((pl = ds->playlist()) != 0) { - pl->get_equivalent_regions (clicked_regionview->region, - results); - } + AudioTimeAxisView* tatv; - for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tatv->view->find_view (**ir)) != 0) { - all_equivalent_regions.push_back (marv); + if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { + + if (tatv->route().edit_group() == group) { + relevant_tracks.insert (tatv); } } - } + + } else { + + /* no active group, or no group */ + + relevant_tracks.insert (atv); } - } else { + } - all_equivalent_regions.push_back (clicked_regionview); + /* step two: apply operation to each track */ + + for (set<AudioTimeAxisView*>::iterator ati = relevant_tracks.begin(); ati != relevant_tracks.end(); ++ati) { + sl (**ati); + } +} +void +Editor::track_set_selected_regionview_from_click (AudioTimeAxisView& atv, AudioRegionView* basis, vector<AudioRegionView*>* all_equivs) +{ + AudioPlaylist* pl; + vector<AudioRegion*> results; + AudioRegionView* marv; + DiskStream* ds; + + if ((ds = atv.get_diskstream()) == 0) { + /* bus */ + return; } - begin_reversible_command (_("set selected regionview")); + if ((pl = ds->playlist()) != 0) { + pl->get_equivalent_regions (basis->region, results); + } - if (add) { + for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = atv.view->find_view (**ir)) != 0) { + all_equivs->push_back (marv); + } + } +} + +void +Editor::set_selected_regionview_from_click (Selection::Operation op, bool no_track_remove) +{ + vector<AudioRegionView*> all_equivalent_regions; + + if (!clicked_regionview) { + return; + } + mapover_audio_tracks (bind (mem_fun (*this, &Editor::track_set_selected_regionview_from_click), + clicked_regionview, &all_equivalent_regions)); + + begin_reversible_command (_("set selected regionview")); + + switch (op) { + case Selection::Toggle: if (clicked_regionview->get_selected()) { - if (group && group->is_active() && selection->audio_regions.size() > 1) { + if (/* group && group->is_active() && */ selection->audio_regions.size() > 1) { /* reduce selection down to just the one clicked */ selection->set (clicked_regionview); } else { selection->remove (clicked_regionview); } } else { - selection->add (all_equivalent_regions); + selection->toggle (all_equivalent_regions); } - set_selected_track_from_click (add, false, no_track_remove); - - } else { + set_selected_track_from_click (op, false, no_track_remove); + break; + case Selection::Set: // karsten wiese suggested these two lines to make // a selected region rise to the top. but this // leads to a mismatch between actual layering @@ -3137,15 +3170,20 @@ Editor::set_selected_regionview_from_click (bool add, bool no_track_remove) } else { selection->set (all_equivalent_regions); - set_selected_track_from_click (add, false, false); + set_selected_track_from_click (op, false, false); } + break; + + case Selection::Extend: + /* not defined yet */ + break; } commit_reversible_command () ; } void -Editor::set_selected_regionview_from_region_list (Region& r, bool add) +Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operation op) { vector<AudioRegionView*> all_equivalent_regions; AudioRegion* region; @@ -3185,13 +3223,16 @@ Editor::set_selected_regionview_from_region_list (Region& r, bool add) begin_reversible_command (_("set selected regions")); - if (add) { - - selection->add (all_equivalent_regions); - - } else { - + switch (op) { + case Selection::Toggle: + selection->toggle (all_equivalent_regions); + break; + case Selection::Set: selection->set (all_equivalent_regions); + break; + case Selection::Extend: + /* not defined yet */ + break; } commit_reversible_command () ; @@ -3597,6 +3638,12 @@ Editor::time_selection_changed () (*i)->show_selection (selection->time); } } + + if (selection->time.empty()) { + ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false); + } else { + ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true); + } } void diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 19c2448f5f..57574d82ba 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -215,8 +215,8 @@ class Editor : public PublicEditor Selection& get_cut_buffer() const { return *cut_buffer; } void play_selection (); - void select_all_in_track (bool add); - void select_all (bool add); + void select_all_in_track (Selection::Operation op); + void select_all (Selection::Operation op); void invert_selection_in_track (); void invert_selection (); @@ -442,11 +442,19 @@ class Editor : public PublicEditor CrossfadeView* clicked_crossfadeview; ControlPoint* clicked_control_point; + void mapover_audio_tracks (sigc::slot<void,AudioTimeAxisView&> sl); + + /* functions to be passed to mapover_audio_tracks(), possibly with sigc::bind()-supplied arguments */ + + void track_set_selected_regionview_from_click (AudioTimeAxisView&, AudioRegionView*, vector<AudioRegionView*>*); + + /* end */ + void catch_vanishing_audio_regionview (AudioRegionView *); - void set_selected_control_point_from_click (bool add = false, bool with_undo = true, bool no_remove=false); - void set_selected_track_from_click (bool add = false, bool with_undo = true, bool no_remove=false); - void set_selected_regionview_from_click (bool add = false, bool no_track_remove=false); - void set_selected_regionview_from_region_list (ARDOUR::Region& region, bool add = false); + void set_selected_control_point_from_click (Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); + void set_selected_track_from_click (Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); + void set_selected_regionview_from_click (Selection::Operation op = Selection::Set, bool no_track_remove=false); + void set_selected_regionview_from_region_list (ARDOUR::Region& region, Selection::Operation op = Selection::Set); bool set_selected_regionview_from_map_event (GdkEventAny*, StreamView*, ARDOUR::Region*); void collect_new_region_view (AudioRegionView *); @@ -1121,7 +1129,9 @@ class Editor : public PublicEditor void start_line_grab_from_line (ArdourCanvas::Item*, GdkEvent*); void start_line_grab (AutomationLine *, GdkEvent*); void start_tempo_marker_grab (ArdourCanvas::Item*, GdkEvent*); + void start_tempo_marker_copy_grab (ArdourCanvas::Item*, GdkEvent*); void start_meter_marker_grab (ArdourCanvas::Item*, GdkEvent*); + void start_meter_marker_copy_grab (ArdourCanvas::Item*, GdkEvent*); void region_view_item_click (AudioRegionView&, GdkEventButton*); @@ -1440,7 +1450,7 @@ class Editor : public PublicEditor void drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event); void end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event); - bool select_all_within (jack_nframes_t start, jack_nframes_t end, gdouble topy, gdouble boty, bool add); + bool select_all_within (jack_nframes_t start, jack_nframes_t end, gdouble topy, gdouble boty, Selection::Operation op); ArdourCanvas::SimpleRect *rubberband_rect; @@ -1616,7 +1626,10 @@ class Editor : public PublicEditor /* audio export */ ExportDialog *export_dialog; + ExportDialog *export_range_markers_dialog; + void export_range (jack_nframes_t start, jack_nframes_t end); + void export_range_markers (); int write_region_selection(AudioRegionSelection&); bool write_region (string path, ARDOUR::AudioRegion&); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 0dfef6f4e9..ece1aa305d 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -82,7 +82,7 @@ Editor::register_actions () act = ActionManager::register_action (editor_actions, "edit-cursor-to-range-end", _("edit cursor to range end"), bind (mem_fun(*this, &Editor::cursor_to_selection_end), edit_cursor)); ActionManager::session_sensitive_actions.push_back (act); - act = ActionManager::register_action (editor_actions, "select-all", _("select all"), bind (mem_fun(*this, &Editor::select_all), false)); + act = ActionManager::register_action (editor_actions, "select-all", _("select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)); ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (editor_actions, "select-all-after-edit-cursor", _("select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)); ActionManager::session_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc index 4964611db3..8ad432ece6 100644 --- a/gtk2_ardour/editor_export_audio.cc +++ b/gtk2_ardour/editor_export_audio.cc @@ -20,14 +20,18 @@ #include <unistd.h> #include <climits> -#include "export_dialog.h" + +#include <gtkmm/messagedialog.h> + +#include "export_session_dialog.h" +#include "export_region_dialog.h" +#include "export_range_markers_dialog.h" #include "editor.h" #include "public_editor.h" #include "selection.h" #include "time_axis_view.h" #include "audio_time_axis.h" #include "regionview.h" -#include "ardour_message.h" #include <pbd/pthread_utils.h> #include <ardour/types.h> @@ -57,12 +61,12 @@ Editor::export_selection () { if (session) { if (selection->time.empty()) { - ArdourMessage message (this, X_("norange"), _("There is no range to export.\n\nSelect a range using the range mouse mode")); + MessageDialog message (*this, _("There is no selection to export.\n\nSelect a selection using the range mouse mode")); + message.run (); return; } - export_range (selection->time.front().start, - selection->time.front().end); + export_range (selection->time.front().start, selection->time.front().end); } } @@ -71,7 +75,7 @@ Editor::export_range (jack_nframes_t start, jack_nframes_t end) { if (session) { if (export_dialog == 0) { - export_dialog = new ExportDialog (*this); + export_dialog = new ExportSessionDialog (*this); } export_dialog->connect_to_session (session); @@ -87,13 +91,36 @@ Editor::export_region () return; } - ExportDialog* dialog = new ExportDialog (*this, &clicked_regionview->region); + ExportDialog* dialog = new ExportRegionDialog (*this, &clicked_regionview->region); dialog->connect_to_session (session); - dialog->set_range (0, clicked_regionview->region.length()); + dialog->set_range ( + clicked_regionview->region.first_frame(), + clicked_regionview->region.last_frame()); dialog->start_export(); } +void +Editor::export_range_markers () +{ + if (session) { + + if (session->locations()->num_range_markers() == 0) { + MessageDialog message (*this, _("There are no ranges to export.\n\nCreate 1 or more ranges by dragging the mouse in the range bar")); + message.run (); + return; + } + + + if (export_range_markers_dialog == 0) { + export_range_markers_dialog = new ExportRangeMarkersDialog(*this); + } + + export_range_markers_dialog->connect_to_session (session); + export_range_markers_dialog->start_export(); + } +} + int Editor::write_region_selection (AudioRegionSelection& regions) { diff --git a/gtk2_ardour/editor_keys.cc b/gtk2_ardour/editor_keys.cc index 226863b88b..00469281fc 100644 --- a/gtk2_ardour/editor_keys.cc +++ b/gtk2_ardour/editor_keys.cc @@ -43,10 +43,10 @@ Editor::keyboard_selection_finish (bool add) { if (session && have_pending_keyboard_selection) { begin_reversible_command (_("keyboard selection")); - if (!add) { - selection->set (0, pending_keyboard_selection_start, session->audible_frame()); - } else { + if (add) { selection->add (pending_keyboard_selection_start, session->audible_frame()); + } else { + selection->set (0, pending_keyboard_selection_start, session->audible_frame()); } commit_reversible_command (); have_pending_keyboard_selection = false; diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index 64ac0fe7e9..d933357685 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -30,10 +30,10 @@ #include "editor.h" #include "marker.h" #include "selection.h" -#include "simplerect.h" #include "editing.h" #include "gui_thread.h" #include "simplerect.h" +#include "actions.h" #include "i18n.h" @@ -564,7 +564,7 @@ Editor::marker_menu_select_all_selectables_using_range () bool is_start; if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) { - select_all_within (l->start(), l->end(), 0, DBL_MAX, false); + select_all_within (l->start(), l->end(), 0, DBL_MAX, Selection::Set); } } diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index ad8522b202..023c500c83 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -314,21 +314,21 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp switch (item_type) { case RegionItem: - set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true); + set_selected_regionview_from_click (Keyboard::selection_type (event->button.state), true); break; case AudioRegionViewNameHighlight: case AudioRegionViewName: - if ((rv = reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))) != 0) { - set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true); + if ((rv = static_cast<AudioRegionView *> (item->get_data ("regionview"))) != 0) { + set_selected_regionview_from_click (Keyboard::selection_type (event->button.state), true); } break; case GainAutomationControlPointItem: case PanAutomationControlPointItem: case RedirectAutomationControlPointItem: - if ((cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) != 0) { - set_selected_control_point_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true); + if ((cp = static_cast<ControlPoint *> (item->get_data ("control_point"))) != 0) { + set_selected_control_point_from_click (Keyboard::selection_type (event->button.state), true); } break; @@ -357,7 +357,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp case StreamItem: case RegionItem: case AutomationTrackItem: - set_selected_track_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true, true); + set_selected_track_from_click (Keyboard::selection_type (event->button.state), true, true); break; case AudioRegionViewNameHighlight: @@ -409,11 +409,19 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return TRUE; case TempoMarkerItem: - start_tempo_marker_grab (item, event); + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + start_tempo_marker_copy_grab (item, event); + } else { + start_tempo_marker_grab (item, event); + } return TRUE; case MeterMarkerItem: - start_meter_marker_grab (item, event); + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + start_meter_marker_copy_grab (item, event); + } else { + start_meter_marker_grab (item, event); + } return TRUE; case TempoBarItem: @@ -2143,6 +2151,39 @@ Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) } void +Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) +{ + Marker* marker; + MeterMarker* meter_marker; + + if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) { + fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg; + /*NOTREACHED*/ + } + + meter_marker = dynamic_cast<MeterMarker*> (marker); + + // create a dummy marker for visual representation of moving the copy. + // The actual copying is not done before we reach the finish callback. + char name[64]; + snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ()); + MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name, + *new MeterSection(meter_marker->meter())); + + drag_info.item = &new_marker->the_item(); + drag_info.copy = true; + drag_info.data = new_marker; + drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback; + drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback; + + start_grab (event); + + drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame(); + + show_verbose_time_cursor (drag_info.current_pointer_frame, 10); +} + +void Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { MeterMarker* marker = (MeterMarker *) drag_info.data; @@ -2175,7 +2216,7 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* { if (drag_info.first_move) return; - meter_marker_drag_motion_callback (item, event); + meter_marker_drag_motion_callback (drag_info.item, event); MeterMarker* marker = (MeterMarker *) drag_info.data; BBT_Time when; @@ -2183,11 +2224,23 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* TempoMap& map (session->tempo_map()); map.bbt_time (drag_info.last_pointer_frame, when); - begin_reversible_command (_("move meter mark")); - session->add_undo (map.get_memento()); - map.move_meter (marker->meter(), when); - session->add_redo_no_execute (map.get_memento()); - commit_reversible_command (); + if (drag_info.copy == true) { + begin_reversible_command (_("copy meter mark")); + session->add_undo (map.get_memento()); + map.add_meter (marker->meter(), when); + session->add_redo_no_execute (map.get_memento()); + commit_reversible_command (); + + // delete the dummy marker we used for visual representation of copying. + // a new visual marker will show up automatically. + delete marker; + } else { + begin_reversible_command (_("move meter mark")); + session->add_undo (map.get_memento()); + map.move_meter (marker->meter(), when); + session->add_redo_no_execute (map.get_memento()); + commit_reversible_command (); + } } void @@ -2224,6 +2277,42 @@ Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) } void +Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) +{ + Marker* marker; + TempoMarker* tempo_marker; + + if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) { + fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; + /*NOTREACHED*/ + } + + if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) { + fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg; + /*NOTREACHED*/ + } + + // create a dummy marker for visual representation of moving the copy. + // The actual copying is not done before we reach the finish callback. + char name[64]; + snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute()); + TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name, + *new TempoSection(tempo_marker->tempo())); + + drag_info.item = &new_marker->the_item(); + drag_info.copy = true; + drag_info.data = new_marker; + drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback; + drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback; + + start_grab (event); + + drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame(); + + show_verbose_time_cursor (drag_info.current_pointer_frame, 10); +} + +void Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { TempoMarker* marker = (TempoMarker *) drag_info.data; @@ -2257,7 +2346,7 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* { if (drag_info.first_move) return; - tempo_marker_drag_motion_callback (item, event); + tempo_marker_drag_motion_callback (drag_info.item, event); TempoMarker* marker = (TempoMarker *) drag_info.data; BBT_Time when; @@ -2265,11 +2354,23 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* TempoMap& map (session->tempo_map()); map.bbt_time (drag_info.last_pointer_frame, when); - begin_reversible_command (_("move tempo mark")); - session->add_undo (map.get_memento()); - map.move_tempo (marker->tempo(), when); - session->add_redo_no_execute (map.get_memento()); - commit_reversible_command (); + if (drag_info.copy == true) { + begin_reversible_command (_("copy tempo mark")); + session->add_undo (map.get_memento()); + map.add_tempo (marker->tempo(), when); + session->add_redo_no_execute (map.get_memento()); + commit_reversible_command (); + + // delete the dummy marker we used for visual representation of copying. + // a new visual marker will show up automatically. + delete marker; + } else { + begin_reversible_command (_("move tempo mark")); + session->add_undo (map.get_memento()); + map.move_tempo (marker->tempo(), when); + session->add_redo_no_execute (map.get_memento()); + commit_reversible_command (); + } } void @@ -4243,7 +4344,7 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) case CreateRangeMarker: begin_reversible_command (_("new range marker")); session->add_undo (session->locations()->get_memento()); - newloc = new Location(temp_location->start(), temp_location->end(), "unnamed"); + newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker); session->locations()->add (newloc, true); session->add_redo_no_execute (session->locations()->get_memento()); commit_reversible_command (); @@ -4453,15 +4554,15 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event) } - bool add = Keyboard::modifier_state_contains (event->button.state, Keyboard::Shift); + Selection::Operation op = Keyboard::selection_type (event->button.state); bool commit; begin_reversible_command (_("select regions")); if (drag_info.grab_frame < drag_info.last_pointer_frame) { - commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, add); + commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op); } else { - commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, add); + commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op); } if (commit) { diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 7a7101d831..747b4d47ec 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -1200,7 +1200,7 @@ Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame) } void -Editor::select_all_in_track (bool add) +Editor::select_all_in_track (Selection::Operation op) { list<Selectable *> touched; @@ -1210,15 +1210,21 @@ Editor::select_all_in_track (bool add) clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched); - if (add) { + switch (op) { + case Selection::Toggle: selection->add (touched); - } else { + break; + case Selection::Set: selection->set (touched); + break; + case Selection::Extend: + /* not defined yet */ + break; } } void -Editor::select_all (bool add) +Editor::select_all (Selection::Operation op) { list<Selectable *> touched; @@ -1229,10 +1235,16 @@ Editor::select_all (bool add) (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched); } begin_reversible_command (_("select all")); - if (add) { + switch (op) { + case Selection::Toggle: selection->add (touched); - } else { + break; + case Selection::Set: selection->set (touched); + break; + case Selection::Extend: + /* not defined yet */ + break; } commit_reversible_command (); } @@ -1266,7 +1278,7 @@ Editor::invert_selection () } bool -Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, bool add) +Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op) { list<Selectable *> touched; @@ -1277,10 +1289,16 @@ Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, (*iter)->get_selectables (start, end, top, bot, touched); } begin_reversible_command (_("select all within")); - if (add) { + switch (op) { + case Selection::Toggle: selection->add (touched); - } else { + break; + case Selection::Set: selection->set (touched); + break; + case Selection::Extend: + /* not defined yet */ + break; } commit_reversible_command (); return !touched.empty(); diff --git a/gtk2_ardour/editor_region_list.cc b/gtk2_ardour/editor_region_list.cc index 034c20f7f0..464a707512 100644 --- a/gtk2_ardour/editor_region_list.cc +++ b/gtk2_ardour/editor_region_list.cc @@ -195,7 +195,7 @@ Editor::region_list_selection_changed() */ if ((iter = region_list_model->get_iter (*i))) { - set_selected_regionview_from_region_list (*((*iter)[region_list_columns.region]), false); + set_selected_regionview_from_region_list (*((*iter)[region_list_columns.region]), Selection::Set); } } } diff --git a/gtk2_ardour/export_dialog.cc b/gtk2_ardour/export_dialog.cc index 1b75bbf49d..8df28965b2 100644 --- a/gtk2_ardour/export_dialog.cc +++ b/gtk2_ardour/export_dialog.cc @@ -26,7 +26,6 @@ #include <fstream> #include <samplerate.h> -#include <pbd/pthread_utils.h> #include <pbd/xml++.h> #include <pbd/dirname.h> @@ -43,7 +42,6 @@ #include "ardour_ui.h" #include "public_editor.h" #include "keyboard.h" -#include "ardour_message.h" #include "i18n.h" @@ -95,7 +93,7 @@ static const gchar* cue_file_types[] = { 0 }; -ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r) +ExportDialog::ExportDialog(PublicEditor& e) : ArdourDialog ("export dialog"), editor (e), format_table (9, 2), @@ -117,9 +115,10 @@ ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r) guint32 len; guint32 maxlen; - audio_region = r; - session = 0; + track_and_master_selection_allowed = true; + channel_count_selection_allowed = true; + export_cd_markers_allowed = true; set_title (_("ardour: export")); set_wmclass (_("ardour_export"), "Ardour"); @@ -177,23 +176,18 @@ ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r) hpacker.set_border_width (5); hpacker.pack_start (format_frame, false, false); - if (!audio_region) { - - master_scroll.add (master_selector); - track_scroll.add (track_selector); - - master_scroll.set_size_request (220, 100); - track_scroll.set_size_request (220, 100); + master_scroll.add (master_selector); + track_scroll.add (track_selector); + master_scroll.set_size_request (220, 100); + track_scroll.set_size_request (220, 100); - - /* we may hide some of these later */ - track_vpacker.pack_start (master_scroll); - track_vpacker.pack_start (track_scroll); - track_vpacker.pack_start (track_selector_button, Gtk::PACK_EXPAND_PADDING); + /* we may hide some of these later */ + track_vpacker.pack_start (master_scroll); + track_vpacker.pack_start (track_scroll); + track_vpacker.pack_start (track_selector_button, Gtk::PACK_EXPAND_PADDING); - hpacker.pack_start (track_vpacker); - } + hpacker.pack_start (track_vpacker); get_vbox()->pack_start (hpacker); @@ -251,7 +245,7 @@ ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r) /* determine longest strings at runtime */ maxlen = 0; - const char *longest = "gl"; + const char *longest = X_("gl"); /* translators: one ascender, one descender */ string longest_str; for (n = 0; n < SNDFILE_HEADER_FORMATS; ++n) { @@ -321,11 +315,9 @@ ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r) format_table.set_col_spacings (5); format_table.set_row_spacings (5); - if (!audio_region) { - format_table.attach (channel_count_label, 0, 1, 0, 1); - format_table.attach (channel_count_combo, 1, 2, 0, 1); - } - + format_table.attach (channel_count_label, 0, 1, 0, 1); + format_table.attach (channel_count_combo, 1, 2, 0, 1); + format_table.attach (header_format_label, 0, 1, 1, 2); format_table.attach (header_format_combo, 1, 2, 1, 2); @@ -375,6 +367,30 @@ ExportDialog::~ExportDialog() } void +ExportDialog::do_not_allow_track_and_master_selection() +{ + track_and_master_selection_allowed = false; + track_vpacker.set_no_show_all(); +} + +void +ExportDialog::do_not_allow_channel_count_selection() +{ + channel_count_selection_allowed = false; + channel_count_combo.set_no_show_all(); + channel_count_label.set_no_show_all(); +} + +void +ExportDialog::do_not_allow_export_cd_markers() +{ + export_cd_markers_allowed = false; + cue_file_label.set_no_show_all(); + cue_file_combo.set_no_show_all(); + cuefile_only_checkbox.set_no_show_all(); +} + +void ExportDialog::connect_to_session (Session *s) { session = s; @@ -571,35 +587,15 @@ ExportDialog::set_range (jack_nframes_t start, jack_nframes_t end) { spec.start_frame = start; spec.end_frame = end; - - if (!audio_region) { - // XXX: this is a hack until we figure out what is really wrong - session->request_locate (spec.start_frame, false); - } } gint ExportDialog::progress_timeout () { - progress_bar.set_fraction (spec.progress/100); + progress_bar.set_fraction (spec.progress); return TRUE; } -void* -ExportDialog::_export_region_thread (void *arg) -{ - PBD::ThreadCreated (pthread_self(), X_("Export Region")); - - static_cast<ExportDialog*>(arg)->export_region (); - return 0; -} - -void -ExportDialog::export_region () -{ - audio_region->exportme (*session, spec); -} - void frames_to_cd_frames_string (char* buf, jack_nframes_t when, jack_nframes_t fr) { @@ -625,8 +621,11 @@ struct LocationSortByStart { void ExportDialog::export_toc_file (Locations::LocationList& locations, const string& path) { + if(!export_cd_markers_allowed){ + return; + } - string filepath = path + ".toc"; + string filepath = path + ".toc"; ofstream out (filepath.c_str()); long unsigned int last_end_time = spec.start_frame, last_start_time = spec.start_frame; int numtracks = 0; @@ -748,7 +747,11 @@ ExportDialog::export_toc_file (Locations::LocationList& locations, const string& void ExportDialog::export_cue_file (Locations::LocationList& locations, const string& path) { - string filepath = path + ".cue"; + if(!export_cd_markers_allowed){ + return; + } + + string filepath = path + ".cue"; ofstream out (filepath.c_str()); gchar buf[18]; long unsigned int last_track_end = spec.start_frame; @@ -867,7 +870,7 @@ ExportDialog::export_cue_file (Locations::LocationList& locations, const string& } } - + void ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_type) { @@ -882,52 +885,21 @@ ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_typ void ExportDialog::do_export () { - // sanity check file name first - string filepath = file_entry.get_text(); - struct stat statbuf; - - if (filepath.empty()) { - // warning dialog - string txt = _("Please enter a valid filename."); - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return; - } - - // check if file exists already and warn - if (stat (filepath.c_str(), &statbuf) == 0) { - if (S_ISDIR (statbuf.st_mode)) { - string txt = _("Please specify a complete filename for the audio file."); - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return; - } - else { - string txt = _("File already exists, do you want to overwrite it?"); - MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true); - //ArdourMessage msg (this, X_("exportoverwrite"), txt, true, false, Gtk::BUTTONS_YES_NO); - if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) { - return; - } - } - } + string filepath = file_entry.get_text(); - // directory needs to exist and be writable - string dirpath = PBD::dirname (filepath); - if (::access (dirpath.c_str(), W_OK) != 0) { - string txt = _("Cannot write file in: ") + dirpath; - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return; - } - - if (cue_file_combo.get_active_text () != _("None")) { - do_export_cd_markers (file_entry.get_text(), cue_file_combo.get_active_text ()); + if(!is_filepath_valid(filepath)){ + return; } - if (cuefile_only_checkbox.get_active()) { - end_dialog (); - return; + if (export_cd_markers_allowed) { + if (cue_file_combo.get_active_text () != _("None")) { + do_export_cd_markers (file_entry.get_text(), cue_file_combo.get_active_text ()); + } + + if (cuefile_only_checkbox.get_active()) { + end_dialog (); + return; + } } ok_button->set_sensitive(false); @@ -935,148 +907,15 @@ ExportDialog::do_export () set_modal (true); - spec.path = filepath; - spec.progress = 0; - spec.running = true; - spec.stop = false; - spec.port_map.clear(); - - if (channel_count_combo.get_active_text() == _("mono")) { - spec.channels = 1; - } else { - spec.channels = 2; - } - - spec.format = 0; - - spec.format |= sndfile_header_format_from_string (header_format_combo.get_active_text ()); - - if ((spec.format & SF_FORMAT_WAV) == 0) { - /* RIFF/WAV specifies endianess */ - spec.format |= sndfile_endian_format_from_string (endian_format_combo.get_active_text ()); - } - - spec.format |= sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ()); - - string sr_str = sample_rate_combo.get_active_text(); - if (sr_str == N_("22.05kHz")) { - spec.sample_rate = 22050; - } else if (sr_str == N_("44.1kHz")) { - spec.sample_rate = 44100; - } else if (sr_str == N_("48kHz")) { - spec.sample_rate = 48000; - } else if (sr_str == N_("88.2kHz")) { - spec.sample_rate = 88200; - } else if (sr_str == N_("96kHz")) { - spec.sample_rate = 96000; - } else if (sr_str == N_("192kHz")) { - spec.sample_rate = 192000; - } else { - spec.sample_rate = session->frame_rate(); - } + // read user input into spec + initSpec(filepath); - string src_str = src_quality_combo.get_active_text(); - if (src_str == _("fastest")) { - spec.src_quality = SRC_ZERO_ORDER_HOLD; - } else if (src_str == _("linear")) { - spec.src_quality = SRC_LINEAR; - } else if (src_str == _("better")) { - spec.src_quality = SRC_SINC_FASTEST; - } else if (src_str == _("intermediate")) { - spec.src_quality = SRC_SINC_MEDIUM_QUALITY; - } else { - spec.src_quality = SRC_SINC_BEST_QUALITY; - } - - string dither_str = dither_type_combo.get_active_text(); - if (dither_str == _("None")) { - spec.dither_type = GDitherNone; - } else if (dither_str == _("Rectangular")) { - spec.dither_type = GDitherRect; - } else if (dither_str == _("Triangular")) { - spec.dither_type = GDitherTri; - } else { - spec.dither_type = GDitherShaped; - } - - if (!audio_region) { - - uint32_t chan=0; - Port *last_port = 0; - - TreeModel::Children rows = master_selector.get_model()->children(); - TreeModel::Children::iterator ri; - TreeModel::Row row; - for (ri = rows.begin(); ri != rows.end(); ++ri) { - row = *ri; - Port* port = row[exp_cols.port]; - - if (last_port != port) { - chan = 0; - } - - if (row[exp_cols.left]) { - spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan)); - } - - if (spec.channels == 2) { - if (row[exp_cols.right]) { - spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan)); - } - } - } - - chan = 0; - - rows = track_selector.get_model()->children(); - for (ri = rows.begin(); ri != rows.end(); ++ri) { - row = *ri; - - Port* port = row[exp_cols.port]; - - if (last_port != port) { - chan = 0; - } - - if (row[exp_cols.left]) { - spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan)); - } - - if (spec.channels == 2) { - if (row[exp_cols.right]) { - spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan)); - } - - } - - last_port = port; - ++chan; - } - } - progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportDialog::progress_timeout), 100); cancel_label.set_text (_("Stop Export")); - if (!audio_region) { - if (session->start_audio_export (spec)) { - goto out; - } - } else { - pthread_t thr; - pthread_create_and_store ("region export", &thr, 0, ExportDialog::_export_region_thread, this); - } - - gtk_main_iteration (); - while (spec.running) { - if (gtk_events_pending()) { - gtk_main_iteration (); - } else { - usleep (10000); - } - } + export_audio_data(); - out: - progress_connection.disconnect (); + progress_connection.disconnect (); end_dialog (); } @@ -1116,7 +955,7 @@ ExportDialog::start_export () return; } - /* If it the filename hasn't been set before, use the + /* If the filename hasn't been set before, use the directory above the current session as a default location for the export. */ @@ -1286,12 +1125,191 @@ ExportDialog::fill_lists () } } + +bool +ExportDialog::is_filepath_valid(string &filepath) +{ + // sanity check file name first + + struct stat statbuf; + + if (filepath.empty()) { + string txt = _("Please enter a valid filename."); + MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); + msg.run(); + return false; + } + + // check if file exists already and warn + + if (stat (filepath.c_str(), &statbuf) == 0) { + if (S_ISDIR (statbuf.st_mode)) { + string txt = _("Please specify a complete filename for the audio file."); + MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); + msg.run(); + return false; + } + else { + string txt = _("File already exists, do you want to overwrite it?"); + MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true); + if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) { + return false; + } + } + } + + // directory needs to exist and be writable + + string dirpath = PBD::dirname (filepath); + if (::access (dirpath.c_str(), W_OK) != 0) { + string txt = _("Cannot write file in: ") + dirpath; + MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); + msg.run(); + return false; + } + + return true; +} + +void +ExportDialog::initSpec(string &filepath) +{ + spec.path = filepath; + spec.progress = 0; + spec.running = true; + spec.stop = false; + spec.port_map.clear(); + + if (channel_count_combo.get_active_text() == _("mono")) { + spec.channels = 1; + } else { + spec.channels = 2; + } + + spec.format = 0; + + spec.format |= sndfile_header_format_from_string (header_format_combo.get_active_text ()); + + if ((spec.format & SF_FORMAT_WAV) == 0) { + /* RIFF/WAV specifies endianess */ + spec.format |= sndfile_endian_format_from_string (endian_format_combo.get_active_text ()); + } + + spec.format |= sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ()); + + string sr_str = sample_rate_combo.get_active_text(); + if (sr_str == N_("22.05kHz")) { + spec.sample_rate = 22050; + } else if (sr_str == N_("44.1kHz")) { + spec.sample_rate = 44100; + } else if (sr_str == N_("48kHz")) { + spec.sample_rate = 48000; + } else if (sr_str == N_("88.2kHz")) { + spec.sample_rate = 88200; + } else if (sr_str == N_("96kHz")) { + spec.sample_rate = 96000; + } else if (sr_str == N_("192kHz")) { + spec.sample_rate = 192000; + } else { + spec.sample_rate = session->frame_rate(); + } + + string src_str = src_quality_combo.get_active_text(); + if (src_str == _("fastest")) { + spec.src_quality = SRC_ZERO_ORDER_HOLD; + } else if (src_str == _("linear")) { + spec.src_quality = SRC_LINEAR; + } else if (src_str == _("better")) { + spec.src_quality = SRC_SINC_FASTEST; + } else if (src_str == _("intermediate")) { + spec.src_quality = SRC_SINC_MEDIUM_QUALITY; + } else { + spec.src_quality = SRC_SINC_BEST_QUALITY; + } + + string dither_str = dither_type_combo.get_active_text(); + if (dither_str == _("None")) { + spec.dither_type = GDitherNone; + } else if (dither_str == _("Rectangular")) { + spec.dither_type = GDitherRect; + } else if (dither_str == _("Triangular")) { + spec.dither_type = GDitherTri; + } else { + spec.dither_type = GDitherShaped; + } + + write_track_and_master_selection_to_spec(); +} + + +void +ExportDialog::write_track_and_master_selection_to_spec() +{ + if(!track_and_master_selection_allowed){ + return; + } + + uint32_t chan=0; + Port *last_port = 0; + + TreeModel::Children rows = master_selector.get_model()->children(); + TreeModel::Children::iterator ri; + TreeModel::Row row; + for (ri = rows.begin(); ri != rows.end(); ++ri) { + row = *ri; + Port* port = row[exp_cols.port]; + + if (last_port != port) { + chan = 0; + } + + if (row[exp_cols.left]) { + spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan)); + } + + if (spec.channels == 2) { + if (row[exp_cols.right]) { + spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan)); + } + } + } + + chan = 0; + rows = track_selector.get_model()->children(); + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + row = *ri; + + Port* port = row[exp_cols.port]; + + if (last_port != port) { + chan = 0; + } + + if (row[exp_cols.left]) { + spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan)); + } + + if (spec.channels == 2) { + if (row[exp_cols.right]) { + spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan)); + } + + } + + last_port = port; + ++chan; + } +} + + gint ExportDialog::window_closed (GdkEventAny *ignored) { end_dialog (); return TRUE; } + void ExportDialog::initiate_browse () { diff --git a/gtk2_ardour/export_dialog.h b/gtk2_ardour/export_dialog.h index c07cebaa96..c67300e0d2 100644 --- a/gtk2_ardour/export_dialog.h +++ b/gtk2_ardour/export_dialog.h @@ -49,15 +49,17 @@ namespace ARDOUR { class ExportDialog : public ArdourDialog { public: - ExportDialog (PublicEditor&, ARDOUR::AudioRegion* r = 0); + ExportDialog (PublicEditor&); ~ExportDialog (); void connect_to_session (ARDOUR::Session*); - void set_range (jack_nframes_t start, jack_nframes_t end); + virtual void set_range (jack_nframes_t start, jack_nframes_t end); void start_export (); protected: - struct ExportModelColumns : public Gtk::TreeModel::ColumnRecord + ARDOUR::AudioExportSpecification spec; + + struct ExportModelColumns : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn<std::string> output; @@ -69,11 +71,41 @@ class ExportDialog : public ArdourDialog }; ExportModelColumns exp_cols; + + // These methods are intended to be used in constructors of subclasses + void do_not_allow_track_and_master_selection(); + void do_not_allow_channel_count_selection(); + void do_not_allow_export_cd_markers(); + + // Checks the given filename for validity when export gets started. + // Export will interrupt when this method returns 'false'. + // Method is responsible for informing user. + virtual bool is_filepath_valid(string &filepath); + + // Gets called from within do_export. Is responsible for exporting the + // audio data. spec has already been filled with user input before calling + // this method. The dialog will be closed after this function exited. + virtual void export_audio_data() = 0; + + // reads the user input and fills spec with the according values + // filepath: complete path to the target file, including filename + void initSpec(string &filepath); + void set_progress_fraction(double progress) { + progress_bar.set_fraction (progress); } + + ARDOUR::Session& getSession() { return *session; }; + string get_selected_header_format() { + return header_format_combo.get_active_text(); }; + string get_selected_file_name() { return file_entry.get_text(); }; + private: PublicEditor& editor; ARDOUR::Session* session; - ARDOUR::AudioRegion* audio_region; + bool track_and_master_selection_allowed; + bool channel_count_selection_allowed; + bool export_cd_markers_allowed; + Gtk::VBox track_vpacker; Gtk::HBox hpacker; @@ -123,10 +155,10 @@ class ExportDialog : public ArdourDialog Gtk::TreeView master_selector; Glib::RefPtr<Gtk::ListStore> master_list; Gtk::FileSelection *file_selector; - ARDOUR::AudioExportSpecification spec; static void *_thread (void *arg); - gint progress_timeout (); + // sets the export progress in the progress bar + virtual gint progress_timeout (); sigc::connection progress_connection; void build_window (); void end_dialog(); @@ -137,8 +169,9 @@ class ExportDialog : public ArdourDialog void cue_file_type_chosen(); void fill_lists(); + void write_track_and_master_selection_to_spec(); - void do_export_cd_markers (const string& path, const string& cuefile_type); + void do_export_cd_markers (const string& path, const string& cuefile_type); void export_cue_file (ARDOUR::Locations::LocationList& locations, const string& path); void export_toc_file (ARDOUR::Locations::LocationList& locations, const string& path); void do_export (); @@ -151,10 +184,6 @@ class ExportDialog : public ArdourDialog void set_state(); void save_state(); - - static void* _export_region_thread (void *); - void export_region (); }; #endif // __ardour_export_dialog_h__ - diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index 1f7c7dc045..81f39f27c5 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -21,6 +21,8 @@ #include <map> #include <vector> +#include <gtkmm/messagedialog.h> + #include <pbd/lockmonitor.h> #include <ardour/io.h> @@ -36,7 +38,6 @@ #include <gtkmm2ext/utils.h> #include "utils.h" -#include "ardour_message.h" #include "io_selector.h" #include "keyboard.h" #include "gui_thread.h" @@ -557,7 +558,8 @@ IOSelector::add_port () } catch (AudioEngine::PortRegistrationFailure& err) { - ArdourMessage msg (0, X_("noport dialog"), _("There are no more JACK ports available.")); + MessageDialog msg (0, _("There are no more JACK ports available.")); + msg.run (); } if (io.input_maximum() >= 0 && io.input_maximum() <= (int) io.n_inputs()) { @@ -575,8 +577,8 @@ IOSelector::add_port () } catch (AudioEngine::PortRegistrationFailure& err) { - ArdourMessage msg (0, X_("noport dialog"), - _("There are no more JACK ports available.")); + MessageDialog msg (0, _("There are no more JACK ports available.")); + msg.run (); } if (io.output_maximum() >= 0 && io.output_maximum() <= (int) io.n_outputs()) { diff --git a/gtk2_ardour/keyboard.cc b/gtk2_ardour/keyboard.cc index de2039620b..c0bbea798a 100644 --- a/gtk2_ardour/keyboard.cc +++ b/gtk2_ardour/keyboard.cc @@ -791,3 +791,14 @@ Keyboard::modifier_state_equals (guint state, ModifierMask mask) return (state & RelevantModifierKeyMask) == (guint) mask; } +Selection::Operation +Keyboard::selection_type (guint state) +{ + if (modifier_state_equals (state, Shift)) { + return Selection::Extend; + } else if (modifier_state_equals (state, Control)) { + return Selection::Toggle; + } else { + return Selection::Set; + } +} diff --git a/gtk2_ardour/keyboard.h b/gtk2_ardour/keyboard.h index 9178546c8e..06ed4c800d 100644 --- a/gtk2_ardour/keyboard.h +++ b/gtk2_ardour/keyboard.h @@ -30,6 +30,8 @@ #include <ardour/types.h> #include <ardour/stateful.h> +#include "selection.h" + using std::vector; using std::string; @@ -71,6 +73,8 @@ class Keyboard : public sigc::trackable, Stateful static bool modifier_state_contains (guint state, ModifierMask); static bool modifier_state_equals (guint state, ModifierMask); + static Selection::Operation selection_type (guint state); + static bool no_modifiers_active (guint state); static void set_meta_modifier (guint); diff --git a/gtk2_ardour/location_ui.cc b/gtk2_ardour/location_ui.cc index c62c7a2e90..21d0fb5b15 100644 --- a/gtk2_ardour/location_ui.cc +++ b/gtk2_ardour/location_ui.cc @@ -784,7 +784,8 @@ LocationUI::add_new_range() { if (session) { jack_nframes_t where = session->audible_frame(); - Location *location = new Location (where, where, "unnamed"); + Location *location = new Location (where, where, "unnamed", + Location::IsRangeMarker); session->begin_reversible_command (_("add range marker")); session->add_undo (session->locations()->get_memento()); session->locations()->add (location, true); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 7ef34f2451..64caac4eef 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -46,7 +46,6 @@ #include "ardour_ui.h" #include "ardour_dialog.h" -#include "ardour_message.h" #include "mixer_strip.h" #include "mixer_ui.h" #include "keyboard.h" @@ -528,8 +527,9 @@ MixerStrip::output_press (GdkEventButton *ev) using namespace Menu_Helpers; if (!_session.engine().connected()) { - ArdourMessage msg (NULL, "nojackdialog", _("Not connected to JACK - no I/O changes are possible")); - return TRUE; + MessageDialog msg (_("Not connected to JACK - no I/O changes are possible")); + msg.run (); + return true; } MenuList& citems = output_menu.items(); @@ -586,8 +586,9 @@ MixerStrip::input_press (GdkEventButton *ev) citems.clear(); if (!_session.engine().connected()) { - ArdourMessage msg (NULL, "nojackdialog", _("Not connected to JACK - no I/O changes are possible")); - return TRUE; + MessageDialog msg (_("Not connected to JACK - no I/O changes are possible")); + msg.run (); + return true; } #if ADVANCED_ROUTE_DISKSTREAM_CONNECTIVITY diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index bf184670a4..a5d0df530d 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -94,6 +94,7 @@ class PublicEditor : public Gtk::Window, public Stateful { virtual bool show_measures () const = 0; virtual void export_session() = 0; virtual void export_selection() = 0; + virtual void export_range_markers() = 0; virtual void register_actions() = 0; virtual void add_toplevel_controls (Gtk::Container&) = 0; virtual void set_zoom_focus (Editing::ZoomFocus) = 0; @@ -172,4 +173,4 @@ class PublicEditor : public Gtk::Window, public Stateful { static PublicEditor* _instance; }; -#endif // __gtk_ardour_public_editor_h__ +#endif // __gtk_ardour_public_editor_h__ diff --git a/gtk2_ardour/redirect_box.cc b/gtk2_ardour/redirect_box.cc index 0936ff378b..2ae34ac4cf 100644 --- a/gtk2_ardour/redirect_box.cc +++ b/gtk2_ardour/redirect_box.cc @@ -23,6 +23,8 @@ #include <sigc++/bind.h> +#include <gtkmm/messagedialog.h> + #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/choice.h> @@ -44,7 +46,6 @@ #include "ardour_ui.h" #include "ardour_dialog.h" -#include "ardour_message.h" #include "public_editor.h" #include "redirect_box.h" #include "keyboard.h" @@ -318,10 +319,7 @@ void RedirectBox::selection_changed () { bool sensitive = (redirect_display.get_selection()->count_selected_rows()) ? true : false; - - for (vector<Glib::RefPtr<Gtk::Action> >::iterator i = ActionManager::plugin_selection_sensitive_actions.begin(); i != ActionManager::plugin_selection_sensitive_actions.end(); ++i) { - (*i)->set_sensitive (sensitive); - } + ActionManager::set_sensitive (ActionManager::plugin_selection_sensitive_actions, sensitive); } void @@ -830,7 +828,8 @@ RedirectBox::paste_redirect_list (list<Redirect*>& redirects) "Copying the set of redirects on the clipboard failed,\n\ probably because the I/O configuration of the plugins\n\ could not match the configuration of this track."); - ArdourMessage am (0, X_("bad redirect copy dialog"), msg); + MessageDialog am (msg); + am.run (); } } @@ -877,7 +876,8 @@ RedirectBox::clone_redirects () "Copying the set of redirects on the clipboard failed,\n\ probably because the I/O configuration of the plugins\n\ could not match the configuration of this track."); - ArdourMessage am (0, X_("bad redirect copy dialog"), msg); + MessageDialog am (msg); + am.run (); } } } @@ -1011,7 +1011,8 @@ RedirectBox::edit_redirect (Redirect* redirect) } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) { if (!_session.engine().connected()) { - ArdourMessage msg (NULL, "nojackdialog", _("Not connected to JACK - no I/O changes are possible")); + MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible")); + msg.run (); return; } diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index f96d649b04..d6efce7264 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -150,6 +150,116 @@ Selection::clear_lines () } void +Selection::toggle (Redirect* r) +{ + if (find (redirects.begin(), redirects.end(), r) == redirects.end()) { + redirects.push_back (r); + RedirectsChanged(); + } +} + +void +Selection::toggle (Playlist* pl) +{ + if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) { + pl->ref (); + playlists.push_back(pl); + PlaylistsChanged (); + } +} + +void +Selection::toggle (const list<Playlist*>& pllist) +{ + bool changed = false; + + for (list<Playlist*>::const_iterator i = pllist.begin(); i != pllist.end(); ++i) { + if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) { + (*i)->ref (); + playlists.push_back (*i); + changed = true; + } + } + + if (changed) { + PlaylistsChanged (); + } +} + +void +Selection::toggle (const list<TimeAxisView*>& track_list) +{ + bool changed = false; + + for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) { + if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) { + void (Selection::*pmf)(TimeAxisView*) = &Selection::remove; + (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i))); + tracks.push_back (*i); + changed = true; + } + } + + if (changed) { + TracksChanged (); + } +} + +void +Selection::toggle (TimeAxisView* track) +{ + if (find (tracks.begin(), tracks.end(), track) == tracks.end()) { + void (Selection::*pmf)(TimeAxisView*) = &Selection::remove; + track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track)); + tracks.push_back (track); + TracksChanged(); + } +} + +void +Selection::toggle (AudioRegionView* r) +{ + if (find (audio_regions.begin(), audio_regions.end(), r) == audio_regions.end()) { + audio_regions.add (r); + RegionsChanged (); + } +} + +void +Selection::toggle (vector<AudioRegionView*>& v) +{ + bool changed = false; + + for (vector<AudioRegionView*>::iterator i = v.begin(); i != v.end(); ++i) { + if (find (audio_regions.begin(), audio_regions.end(), (*i)) == audio_regions.end()) { + audio_regions.add ((*i)); + changed = true; + } + } + + if (changed) { + RegionsChanged (); + } +} + +long +Selection::toggle (jack_nframes_t start, jack_nframes_t end) +{ + AudioRangeComparator cmp; + + /* XXX this implementation is incorrect */ + + time.push_back (AudioRange (start, end, next_time_id++)); + time.consolidate (); + time.sort (cmp); + + TimeChanged (); + + return next_time_id - 1; +} + + +void Selection::add (Redirect* r) { if (find (redirects.begin(), redirects.end(), r) == redirects.end()) { @@ -247,6 +357,8 @@ Selection::add (jack_nframes_t start, jack_nframes_t end) { AudioRangeComparator cmp; + /* XXX this implementation is incorrect */ + time.push_back (AudioRange (start, end, next_time_id++)); time.consolidate (); time.sort (cmp); diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index ffda6a0b0f..ebeda1aea7 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -21,6 +21,8 @@ #ifndef __ardour_gtk_selection_h__ #define __ardour_gtk_selection_h__ +#include <vector> + #include <sigc++/signal.h> #include "time_selection.h" @@ -35,6 +37,14 @@ class TimeAxisView; class AudioRegionView; class Selectable; +namespace ARDOUR { + class Region; + class AudioRegion; + class Playlist; + class Redirect; + class AutomationList; +} + class Selection : public sigc::trackable { public: @@ -43,6 +53,12 @@ class Selection : public sigc::trackable Range = 0x2 }; + enum Operation { + Set, + Toggle, + Extend + }; + TrackSelection tracks; AudioRegionSelection audio_regions; TimeSelection time; @@ -88,6 +104,16 @@ class Selection : public sigc::trackable void set (ARDOUR::Redirect*); void set (AutomationSelectable*); + void toggle (TimeAxisView*); + void toggle (const list<TimeAxisView*>&); + void toggle (AudioRegionView*); + void toggle (std::vector<AudioRegionView*>&); + long toggle (jack_nframes_t, jack_nframes_t); + void toggle (ARDOUR::AutomationList*); + void toggle (ARDOUR::Playlist*); + void toggle (const list<ARDOUR::Playlist*>&); + void toggle (ARDOUR::Redirect*); + void add (TimeAxisView*); void add (const list<TimeAxisView*>&); void add (AudioRegionView*); @@ -97,7 +123,7 @@ class Selection : public sigc::trackable void add (ARDOUR::Playlist*); void add (const list<ARDOUR::Playlist*>&); void add (ARDOUR::Redirect*); - + void remove (TimeAxisView*); void remove (const list<TimeAxisView*>&); void remove (AudioRegionView*); @@ -126,7 +152,7 @@ class Selection : public sigc::trackable private: uint32_t next_time_id; - void add (vector<AutomationSelectable*>&); + void add (std::vector<AutomationSelectable*>&); }; bool operator==(const Selection& a, const Selection& b); diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index e609d0e33b..393f919d95 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -407,7 +407,7 @@ pane_handler (GdkEventButton* ev, Gtk::Paned* pane) /* already collapsed: restore it (note that this is cast from a pointer value to int, which is tricky on 64bit */ - pane->set_position ((gint64) pane->get_data ("rpos")); + pane->set_position ((intptr_t) pane->get_data ("rpos")); } else { @@ -419,7 +419,7 @@ pane_handler (GdkEventButton* ev, Gtk::Paned* pane) /* collapse to show the relevant child in full */ - collapse_direction = (gint64) pane->get_data ("collapse-direction"); + collapse_direction = (intptr_t) pane->get_data ("collapse-direction"); if (collapse_direction) { pane->set_position (1); diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index 0ef4c45f16..4dae06eeff 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -28,6 +28,7 @@ namespace ARDOUR { class Session; class DiskStream; class AudioPlaylist; +class RouteGroup; class AudioTrack : public Route { diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h index 1da67c78da..3728d0b346 100644 --- a/libs/ardour/ardour/location.h +++ b/libs/ardour/ardour/location.h @@ -50,7 +50,8 @@ class Location : public Stateful, public sigc::trackable IsAutoLoop = 0x4, IsHidden = 0x8, IsCDMarker = 0x10, - IsEnd = 0x20 + IsEnd = 0x20, + IsRangeMarker = 0x40 }; Location (jack_nframes_t sample_start, @@ -95,6 +96,7 @@ class Location : public Stateful, public sigc::trackable bool is_hidden () { return _flags & IsHidden; } bool is_cd_marker () { return _flags & IsCDMarker; } bool is_end() { return _flags & IsEnd; } + bool is_range_marker() { return _flags & IsRangeMarker; } sigc::signal<void,Location*> name_changed; sigc::signal<void,Location*> end_changed; @@ -145,6 +147,8 @@ class Locations : public Stateful, public StateManager Location* auto_punch_location () const; Location* end_location() const; + uint32_t num_range_markers() const; + int set_current (Location *, bool want_lock = true); Location *current () const { return current_location; } @@ -179,7 +183,7 @@ class Locations : public Stateful, public StateManager LocationList locations; Location *current_location; - PBD::Lock lock; + mutable PBD::Lock lock; int set_current_unlocked (Location *); void location_changed (Location*); diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h index 910500ccf8..ad523da9c7 100644 --- a/libs/ardour/ardour/route_group.h +++ b/libs/ardour/ardour/route_group.h @@ -22,6 +22,7 @@ #define __ardour_route_group_h__ #include <list> +#include <set> #include <string> #include <stdint.h> #include <sigc++/signal.h> @@ -84,6 +85,10 @@ class RouteGroup : public Stateful, public sigc::trackable { template<class T> void apply (void (AudioTrack::*func)(T, void *), T val, void *src); + /* fills at_set with all members of the group that are AudioTracks */ + + void audio_track_group (std::set<AudioTrack*>& at_set); + void clear () { routes.clear (); changed(); diff --git a/libs/ardour/ardour/route_group_specialized.h b/libs/ardour/ardour/route_group_specialized.h index 32c627eb7a..0424002dcd 100644 --- a/libs/ardour/ardour/route_group_specialized.h +++ b/libs/ardour/ardour/route_group_specialized.h @@ -16,7 +16,7 @@ RouteGroup::apply (void (AudioTrack::*func)(T, void *), T val, void *src) } } } - + } /* namespace ARDOUR */ #endif /* __ardour_route_group_specialized_h__ */ diff --git a/libs/ardour/ardour/sndfile_helpers.h b/libs/ardour/ardour/sndfile_helpers.h index 4a2c38eac3..bae73a0377 100644 --- a/libs/ardour/ardour/sndfile_helpers.h +++ b/libs/ardour/ardour/sndfile_helpers.h @@ -10,6 +10,7 @@ using std::string; #define SNDFILE_HEADER_FORMATS 7 extern const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1]; +extern const char * const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1]; extern int sndfile_header_formats[SNDFILE_HEADER_FORMATS]; @@ -26,6 +27,7 @@ extern int sndfile_endian_formats[SNDFILE_ENDIAN_FORMATS]; int sndfile_bitdepth_format_from_string(string); int sndfile_header_format_from_string(string); int sndfile_endian_format_from_string(string); +string sndfile_file_ending_from_string(string); int sndfile_data_width (int format); diff --git a/libs/ardour/i18n.h b/libs/ardour/i18n.h index 7c79d2eb53..3ace250419 100644 --- a/libs/ardour/i18n.h +++ b/libs/ardour/i18n.h @@ -4,8 +4,13 @@ #include <pbd/compose.h> #include "gettext.h" -#define _(Text) dgettext (PACKAGE, Text) +#include <vector> +#include <string> + +std::vector<std::string> internationalize (const char **); + +#define _(Text) dgettext (PACKAGE,Text) #define N_(Text) gettext_noop (Text) -#define X_(Text) (Text) +#define X_(Text) Text #endif // __i18n_h__ diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index 6008f3d70b..972384cc32 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -719,3 +719,16 @@ Locations::get_memento () const { return sigc::bind (mem_fun (*(const_cast<Locations*> (this)), &StateManager::use_state), _current_state_id); } + +uint32_t +Locations::num_range_markers () const +{ + uint32_t cnt = 0; + LockMonitor lm (lock, __LINE__, __FILE__); + for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) { + if ((*i)->is_range_marker()) { + ++cnt; + } + } + return cnt; +} diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index 225224e684..3d40483634 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -28,6 +28,7 @@ #include <pbd/error.h> #include <ardour/route_group.h> +#include <ardour/audio_track.h> #include <ardour/diskstream.h> #include <ardour/configuration.h> @@ -182,3 +183,15 @@ RouteGroup::set_hidden (bool yn, void *src) } FlagsChanged (src); /* EMIT SIGNAL */ } + +void +RouteGroup::audio_track_group (set<AudioTrack*>& ats) +{ + for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) { + AudioTrack* at = dynamic_cast<AudioTrack*>(*i); + if (at) { + ats.insert (at); + } + } +} + diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc index 2fd9e63ce2..21d8c72b2b 100644 --- a/libs/ardour/sndfile_helpers.cc +++ b/libs/ardour/sndfile_helpers.cc @@ -1,12 +1,13 @@ #include <map> +#include <vector> #include <sndfile.h> - #include <ardour/sndfile_helpers.h> #include "i18n.h" using std::map; +using namespace std; const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1] = { N_("WAV"), @@ -19,6 +20,17 @@ const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1] = { 0 }; +const char* const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1] = { + N_(".wav"), + N_(".aiff"), + N_(".raw"), + N_(".paf"), + N_(".au"), + N_(".ircam"), + N_(".w64"), + 0 +}; + int sndfile_header_formats[SNDFILE_HEADER_FORMATS] = { SF_FORMAT_WAV, SF_FORMAT_AIFF, @@ -90,6 +102,23 @@ sndfile_endian_format_from_string (string str) return -1; } +string +sndfile_file_ending_from_string (string str) +{ + static vector<string> file_endings; + + if (file_endings.empty()) { + file_endings = internationalize((const char **) sndfile_file_endings_strings); + } + + for (int n = 0; sndfile_header_formats_strings[n]; ++n) { + if (str == sndfile_header_formats_strings[n]) { + return file_endings[n]; + } + } + return 0; +} + int sndfile_data_width (int format) { |