mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 06:44:57 +01:00
697 lines
22 KiB
C++
697 lines
22 KiB
C++
/*
|
|
* Copyright (C) 2025 Robin Gareus <robin@gareus.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <ytkmm/sizegroup.h>
|
|
#include <ytkmm/stock.h>
|
|
|
|
#include "pbd/basename.h"
|
|
#include "pbd/file_utils.h"
|
|
#include "pbd/replace_all.h"
|
|
|
|
#include "ardour/directory_names.h"
|
|
#include "ardour/filename_extensions.h"
|
|
#include "ardour/filesystem_paths.h"
|
|
#include "ardour/recent_sessions.h"
|
|
#include "ardour/session.h"
|
|
|
|
#include "gtkmm2ext/utils.h"
|
|
|
|
#include "widgets/ardour_button.h"
|
|
#include "widgets/ardour_dropdown.h"
|
|
#include "widgets/ardour_spacer.h"
|
|
|
|
#include "strip_import_dialog.h"
|
|
|
|
#include "pbd/i18n.h"
|
|
|
|
using namespace Gtk;
|
|
using namespace std;
|
|
using namespace PBD;
|
|
using namespace ARDOUR;
|
|
using namespace ArdourWidgets;
|
|
|
|
StripImportDialog::StripImportDialog (Session* s)
|
|
: ArdourDialog (_("Import Track/Bus State"))
|
|
, _add_rid (0)
|
|
, _add_eid (0)
|
|
{
|
|
set_session (s);
|
|
|
|
_open_button = manage (new Button (Stock::GO_FORWARD));
|
|
_ok_button = manage (new Button (Stock::OK));
|
|
|
|
get_action_area ()->pack_start (_info_text);
|
|
add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
|
get_action_area ()->pack_end (*_open_button);
|
|
get_action_area ()->pack_end (*_ok_button);
|
|
|
|
_open_button->show ();
|
|
_ok_button->hide ();
|
|
|
|
_open_button->signal_clicked ().connect (mem_fun (*this, &StripImportDialog::maybe_switch_to_import_page), false);
|
|
_ok_button->signal_clicked ().connect (mem_fun (*this, &StripImportDialog::ok_activated), false);
|
|
|
|
_open_button->set_sensitive (false);
|
|
_ok_button->set_sensitive (false);
|
|
|
|
get_vbox ()->pack_start (_page_file);
|
|
setup_file_page ();
|
|
}
|
|
|
|
StripImportDialog::~StripImportDialog ()
|
|
{
|
|
_notebook_connection.disconnect ();
|
|
_chooser_connection.disconnect ();
|
|
}
|
|
|
|
/* ****************************************************************************
|
|
* Page One .. pick file to import
|
|
*/
|
|
|
|
void
|
|
StripImportDialog::setup_file_page ()
|
|
{
|
|
/* file-chooser */
|
|
_chooser.set_size_request (450, 300);
|
|
_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir ()));
|
|
|
|
FileFilter tracks_filter;
|
|
tracks_filter.add_pattern (string_compose (X_("*%1"), routestate_suffix));
|
|
tracks_filter.set_name (string_compose (_("%1 tracks"), PROGRAM_NAME));
|
|
_chooser.add_filter (tracks_filter);
|
|
|
|
FileFilter template_filter;
|
|
template_filter.add_pattern (string_compose (X_("*%1"), template_suffix));
|
|
template_filter.set_name (string_compose (_("%1 tracks"), PROGRAM_NAME));
|
|
_chooser.add_filter (template_filter);
|
|
|
|
FileFilter session_filter;
|
|
session_filter.add_pattern (string_compose (X_("*%1"), ARDOUR::statefile_suffix));
|
|
session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
|
|
_chooser.add_filter (session_filter);
|
|
|
|
FileFilter all_filter;
|
|
all_filter.add_pattern (string_compose (X_("*%1"), ARDOUR::statefile_suffix));
|
|
all_filter.add_pattern (string_compose (X_("*%1"), template_suffix));
|
|
all_filter.add_pattern (string_compose (X_("*%1"), routestate_suffix));
|
|
all_filter.set_name (_("All supported files"));
|
|
_chooser.add_filter (all_filter);
|
|
_chooser.set_filter (all_filter);
|
|
|
|
Gtkmm2ext::add_volume_shortcuts (_chooser);
|
|
|
|
_chooser_connection = _chooser.signal_selection_changed ().connect (mem_fun (*this, &StripImportDialog::file_selection_changed));
|
|
_chooser.signal_file_activated ().connect (sigc::mem_fun (*this, &StripImportDialog::maybe_switch_to_import_page));
|
|
|
|
_notebook.append_page (_chooser, _("File"));
|
|
|
|
guint page = 1;
|
|
|
|
/* recent Sessions */
|
|
ARDOUR::RecentSessions rs;
|
|
ARDOUR::read_recent_sessions (rs);
|
|
|
|
if (!rs.empty ()) {
|
|
_recent_model = TreeStore::create (_columns);
|
|
|
|
/* setup model - compare to SessionDialog::redisplay_recent_sessions */
|
|
for (auto const& [_, dir] : rs) {
|
|
string dirname = dir;
|
|
if (dirname.empty ()) {
|
|
continue;
|
|
}
|
|
if (dirname[dirname.length () - 1] == '/') {
|
|
dirname = dirname.substr (0, dirname.length () - 1);
|
|
}
|
|
/* check whether session still exists */
|
|
if (!Glib::file_test (dirname, Glib::FILE_TEST_EXISTS)) {
|
|
/* session doesn't exist */
|
|
continue;
|
|
}
|
|
/* now get available states for this session */
|
|
vector<string> state_file_names = Session::possible_states (dirname);
|
|
if (state_file_names.empty ()) {
|
|
/* no state file? */
|
|
continue;
|
|
}
|
|
TreeModel::Row row = *(_recent_model->append ());
|
|
if (state_file_names.size () > 1) {
|
|
row[_columns.name] = PBD::basename_nosuffix (dirname);
|
|
row[_columns.path] = "";
|
|
for (auto const& snap : state_file_names) {
|
|
Gtk::TreeModel::Row child_row = *(_recent_model->append (row.children ()));
|
|
child_row[_columns.name] = snap;
|
|
child_row[_columns.path] = Glib::build_filename (dirname, snap + statefile_suffix);
|
|
}
|
|
} else {
|
|
row[_columns.name] = state_file_names.front ();
|
|
row[_columns.path] = Glib::build_filename (dirname, state_file_names.front () + statefile_suffix);
|
|
}
|
|
}
|
|
|
|
_recent_treeview.set_model (_recent_model);
|
|
_recent_treeview.append_column (_("Session Name"), _columns.name);
|
|
_recent_treeview.set_headers_visible (true);
|
|
_recent_treeview.get_selection ()->set_mode (SELECTION_SINGLE);
|
|
|
|
_recent_treeview.get_selection ()->signal_changed ().connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::treeview_selection_changed), &_recent_treeview, Snapshot));
|
|
_recent_treeview.signal_row_activated ().connect ([&] (const TreeModel::Path&, TreeViewColumn*) { maybe_switch_to_import_page (); });
|
|
|
|
_recent_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
|
|
_recent_scroller.add (_recent_treeview);
|
|
|
|
_notebook.append_page (_recent_scroller, _("Recent Sessions"));
|
|
|
|
_notebook_type[page] = Snapshot;
|
|
_notebook_content[page++] = &_recent_treeview;
|
|
}
|
|
|
|
/* template list */
|
|
vector<TemplateInfo> templates;
|
|
find_session_templates (templates, false);
|
|
|
|
if (templates.size () > 0) {
|
|
_template_model = ListStore::create (_columns);
|
|
setup_model (_template_model, templates);
|
|
|
|
_template_treeview.set_model (_template_model);
|
|
_template_treeview.append_column (_("Name"), _columns.name);
|
|
_template_treeview.set_headers_visible (true);
|
|
|
|
_template_treeview.get_selection ()->signal_changed ().connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::treeview_selection_changed), &_template_treeview, Template));
|
|
_template_treeview.signal_row_activated ().connect ([&] (const TreeModel::Path&, TreeViewColumn*) { maybe_switch_to_import_page (); });
|
|
|
|
_template_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
|
|
_template_scroller.add (_template_treeview);
|
|
|
|
_notebook.append_page (_template_scroller, _("Session Templates"));
|
|
|
|
_notebook_type[page] = Template;
|
|
_notebook_content[page++] = &_template_treeview;
|
|
}
|
|
|
|
templates.clear ();
|
|
Searchpath local_path (_session->path ());
|
|
local_path.add_subdirectory_to_paths (routestates_dir_name);
|
|
find_presets (local_path, templates);
|
|
if (templates.size () > 0) {
|
|
_local_pset_model = ListStore::create (_columns);
|
|
setup_model (_local_pset_model, templates);
|
|
|
|
_local_pset_treeview.set_model (_local_pset_model);
|
|
_local_pset_treeview.append_column (_("Name"), _columns.name);
|
|
_local_pset_treeview.set_headers_visible (true);
|
|
|
|
_local_pset_treeview.get_selection ()->signal_changed ().connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::treeview_selection_changed), &_local_pset_treeview, RouteState));
|
|
_local_pset_treeview.signal_row_activated ().connect ([&] (const TreeModel::Path&, TreeViewColumn*) { maybe_switch_to_import_page (); });
|
|
|
|
_local_pset_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
|
|
_local_pset_scroller.add (_local_pset_treeview);
|
|
|
|
_notebook.append_page (_local_pset_scroller, _("Local Strip Templates"));
|
|
|
|
_notebook_type[page] = RouteState;
|
|
_notebook_content[page++] = &_local_pset_treeview;
|
|
}
|
|
|
|
templates.clear ();
|
|
Searchpath global_path (ardour_data_search_path ());
|
|
global_path.add_subdirectory_to_paths (routestates_dir_name);
|
|
find_presets (global_path, templates);
|
|
if (templates.size () > 0) {
|
|
_global_pset_model = ListStore::create (_columns);
|
|
setup_model (_global_pset_model, templates);
|
|
|
|
_global_pset_treeview.set_model (_global_pset_model);
|
|
_global_pset_treeview.append_column (_("Name"), _columns.name);
|
|
_global_pset_treeview.set_headers_visible (true);
|
|
|
|
_global_pset_treeview.get_selection ()->signal_changed ().connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::treeview_selection_changed), &_global_pset_treeview, RouteState));
|
|
_global_pset_treeview.signal_row_activated ().connect ([&] (const TreeModel::Path&, TreeViewColumn*) { maybe_switch_to_import_page (); });
|
|
|
|
_global_pset_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
|
|
_global_pset_scroller.add (_global_pset_treeview);
|
|
|
|
_notebook.append_page (_global_pset_scroller, _("Global Strip Templates"));
|
|
|
|
_notebook_type[page] = RouteState;
|
|
_notebook_content[page++] = &_global_pset_treeview;
|
|
}
|
|
|
|
_notebook_connection = _notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &StripImportDialog::page_changed));
|
|
|
|
_page_file.pack_start (_notebook);
|
|
_page_file.show_all ();
|
|
|
|
if (!rs.empty ()) {
|
|
_notebook.set_current_page (1);
|
|
} else if (page > 1) {
|
|
_notebook.set_current_page (page - 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::page_changed (GtkNotebookPage*, guint page)
|
|
{
|
|
switch (page) {
|
|
case 0:
|
|
file_selection_changed ();
|
|
break;
|
|
default:
|
|
treeview_selection_changed (_notebook_content.at (page), _notebook_type.at (page));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::setup_model (Glib::RefPtr<Gtk::ListStore> model, vector<TemplateInfo> const& templates)
|
|
{
|
|
for (auto const& t : templates) {
|
|
TreeModel::Row row;
|
|
row = *(model->append ());
|
|
|
|
row[_columns.name] = t.name;
|
|
row[_columns.path] = t.path;
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::find_presets (Searchpath const& search_path, vector<TemplateInfo>& template_info)
|
|
{
|
|
vector<string> templates;
|
|
|
|
/* clang-format off */
|
|
find_paths_matching_filter (templates,
|
|
search_path,
|
|
[] (const string& str, void*) { return Glib::file_test (str, Glib::FILE_TEST_IS_DIR); },
|
|
0, true, true);
|
|
/* clang-format on */
|
|
|
|
if (templates.empty ()) {
|
|
return;
|
|
}
|
|
|
|
for (vector<string>::iterator i = templates.begin (); i != templates.end (); ++i) {
|
|
string file = session_template_dir_to_file (*i);
|
|
|
|
TemplateInfo rti;
|
|
rti.name = Glib::path_get_basename (*i);
|
|
rti.path = *i;
|
|
|
|
template_info.push_back (rti);
|
|
}
|
|
std::sort (template_info.begin (), template_info.end ());
|
|
}
|
|
|
|
void
|
|
StripImportDialog::file_selection_changed ()
|
|
{
|
|
parse_route_state (_chooser.get_filename ());
|
|
}
|
|
|
|
static string
|
|
template_dir_to_file (string const& dir, string const& suffix)
|
|
{
|
|
return Glib::build_filename (dir, Glib::path_get_basename (dir) + suffix);
|
|
}
|
|
|
|
void
|
|
StripImportDialog::treeview_selection_changed (Gtk::TreeView* treeview, SelectionType t)
|
|
{
|
|
Gtk::TreeModel::const_iterator selection = treeview->get_selection ()->get_selected ();
|
|
if (selection) {
|
|
switch (t) {
|
|
case Template:
|
|
parse_route_state (template_dir_to_file ((*selection)[_columns.path], template_suffix));
|
|
break;
|
|
case RouteState:
|
|
parse_route_state (template_dir_to_file ((*selection)[_columns.path], routestate_suffix));
|
|
break;
|
|
case Snapshot:
|
|
parse_route_state ((*selection)[_columns.path]);
|
|
break;
|
|
}
|
|
} else {
|
|
parse_route_state ("");
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::parse_route_state (std::string const& path)
|
|
{
|
|
_extern_map.clear ();
|
|
_path = path;
|
|
|
|
if (path.empty ()) {
|
|
goto out;
|
|
}
|
|
if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
|
|
goto out;
|
|
}
|
|
|
|
_extern_map = _session->parse_route_state (path, _match_pbd_id);
|
|
|
|
out:
|
|
if (_extern_map.empty ()) {
|
|
_info_text.set_text ("");
|
|
_info_text.hide ();
|
|
} else {
|
|
_info_text.set_text (string_compose (P_("%1 Track", "%1 Tracks", _extern_map.size ()), _extern_map.size ()));
|
|
_info_text.show ();
|
|
}
|
|
_open_button->set_sensitive (!_extern_map.empty ());
|
|
}
|
|
|
|
void
|
|
StripImportDialog::maybe_switch_to_import_page ()
|
|
{
|
|
if (_extern_map.empty ()) {
|
|
return;
|
|
}
|
|
|
|
// TODO cleanup managed items on _page_file
|
|
|
|
/* -> next page */
|
|
setup_strip_import_page ();
|
|
get_vbox ()->remove (_page_file);
|
|
get_vbox ()->pack_start (_page_strip);
|
|
|
|
_info_text.hide ();
|
|
_open_button->hide ();
|
|
_ok_button->show ();
|
|
}
|
|
|
|
/* ****************************************************************************
|
|
* Page Two map Tracks/State
|
|
*/
|
|
|
|
void
|
|
StripImportDialog::refill_import_table ()
|
|
{
|
|
Gtk::Label* l;
|
|
Gtkmm2ext::container_clear (_strip_table, true);
|
|
|
|
_strip_table.set_spacings (3);
|
|
|
|
Glib::RefPtr<SizeGroup> col_size_group (SizeGroup::create (SIZE_GROUP_HORIZONTAL));
|
|
|
|
l = manage (new Label (string_compose ("<b>%1</b>", _("Local Track/Bus"))));
|
|
l->set_use_markup ();
|
|
_strip_table.attach (*l, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK);
|
|
col_size_group->add_widget (*l);
|
|
|
|
l = manage (new Label (string_compose ("<b>%1</b>", _("External State"))));
|
|
l->set_use_markup ();
|
|
_strip_table.attach (*l, 2, 3, 0, 1, Gtk::FILL, Gtk::SHRINK);
|
|
col_size_group->add_widget (*l);
|
|
|
|
/* clang-format off */
|
|
_strip_table.attach (*manage (new ArdourVSpacer (1.0)), 1, 2, 0, 1, SHRINK , EXPAND | FILL, 8, 4);
|
|
_strip_table.attach (*manage (new ArdourHSpacer (1.0)), 0, 4, 1, 2, EXPAND | FILL, SHRINK, 4, 8);
|
|
/* clang-format on */
|
|
|
|
std::vector<std::pair<PBD::ID, PBD::ID>> sorted_map;
|
|
for (auto const& i : _import_map) {
|
|
sorted_map.push_back (i);
|
|
}
|
|
std::sort (sorted_map.begin (), sorted_map.end (), [=] (auto& a, auto& b) {
|
|
try {
|
|
return _route_map.at (a.first).pi.order () < _route_map.at (b.first).pi.order ();
|
|
} catch (...) {
|
|
}
|
|
return a.second < b.second;
|
|
});
|
|
|
|
/* Refill table */
|
|
int r = 1;
|
|
for (auto& [rid, eid] : sorted_map /*_import_map*/) {
|
|
++r;
|
|
if (_route_map.find (rid) != _route_map.end ()) {
|
|
l = manage (new Label (_route_map.at (rid).name, 0, 0.5));
|
|
} else {
|
|
l = manage (new Label (_("<i>New Track</i>"), 0, 0.5));
|
|
l->set_use_markup ();
|
|
}
|
|
_strip_table.attach (*l, 0, 1, r, r + 1, EXPAND | FILL, SHRINK);
|
|
#if 0
|
|
l = manage (new Label (_extern_map[eid], 1.0, 0.5));
|
|
_strip_table.attach (*l, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
|
#else
|
|
using namespace Menu_Helpers;
|
|
ArdourDropdown* dd = manage (new ArdourDropdown ());
|
|
for (auto& [eid, einfo] : _extern_map) {
|
|
dd->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (einfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::change_mapping), dd, rid, eid, einfo.name)));
|
|
}
|
|
dd->set_text (_extern_map.at (eid).name);
|
|
_strip_table.attach (*dd, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
|
#endif
|
|
|
|
ArdourButton* rm = manage (new ArdourButton ());
|
|
rm->set_icon (ArdourIcon::CloseCross);
|
|
rm->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::remove_mapping), rid));
|
|
_strip_table.attach (*rm, 3, 4, r, r + 1, Gtk::SHRINK, Gtk::SHRINK, 4, 2);
|
|
}
|
|
|
|
if (r > 1) {
|
|
++r;
|
|
_strip_table.attach (*manage (new ArdourVSpacer (1.0)), 1, 2, 2, r, SHRINK, EXPAND | FILL, 8, 4);
|
|
++r;
|
|
_strip_table.attach (*manage (new ArdourHSpacer (1.0)), 0, 4, r, r + 1, EXPAND | FILL, SHRINK, 4, 8);
|
|
}
|
|
|
|
++r;
|
|
|
|
/* Add options */
|
|
using namespace Menu_Helpers;
|
|
|
|
_add_rid = PBD::ID (0);
|
|
_add_eid = PBD::ID (0);
|
|
|
|
int64_t next_id = std::numeric_limits<uint64_t>::max () - 1;
|
|
PBD::ID next_new = PBD::ID (next_id);
|
|
|
|
while (_import_map.find (next_new) != _import_map.end ()) {
|
|
--next_id;
|
|
next_new = PBD::ID (next_id);
|
|
}
|
|
|
|
/* accumulate both dropdowns, so columns are equally spaced */
|
|
std::vector<std::string> sizing_texts;
|
|
|
|
_add_rid_dropdown = manage (new ArdourWidgets::ArdourDropdown ());
|
|
_add_rid_dropdown->add_menu_elem (MenuElem (_(" -- New Track -- "), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, next_new, _("New Track"))));
|
|
sizing_texts.push_back (_(" -- New Track -- "));
|
|
|
|
for (auto& [rid, rinfo] : _route_map) {
|
|
if (_import_map.find (rid) != _import_map.end ()) {
|
|
continue;
|
|
}
|
|
_add_rid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (rinfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, rid, rinfo.name)));
|
|
sizing_texts.push_back (rinfo.name);
|
|
}
|
|
|
|
_add_eid_dropdown = manage (new ArdourWidgets::ArdourDropdown ());
|
|
for (auto& [eid, einfo] : _extern_map) {
|
|
_add_eid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (einfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), true, eid, einfo.name)));
|
|
sizing_texts.push_back (einfo.name);
|
|
}
|
|
|
|
_add_rid_dropdown->set_sizing_texts (sizing_texts);
|
|
_add_eid_dropdown->set_sizing_texts (sizing_texts);
|
|
col_size_group->add_widget (*_add_rid_dropdown);
|
|
col_size_group->add_widget (*_add_eid_dropdown);
|
|
|
|
_add_new_mapping = manage (new ArdourButton ());
|
|
_add_new_mapping->set_icon (ArdourIcon::PlusSign);
|
|
_add_new_mapping->signal_clicked.connect (sigc::mem_fun (*this, &StripImportDialog::add_mapping));
|
|
|
|
/* clang-format off */
|
|
_strip_table.attach (*_add_rid_dropdown, 0, 1, r, r + 1, EXPAND | FILL, SHRINK);
|
|
_strip_table.attach (*_add_eid_dropdown, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
|
_strip_table.attach (*_add_new_mapping, 3, 4, r, r + 1, Gtk::SHRINK, SHRINK);
|
|
/* clang-format on */
|
|
|
|
bool can_add = !_add_rid_dropdown->items ().empty () && !_add_eid_dropdown->items ().empty ();
|
|
|
|
_add_rid_dropdown->set_sensitive (can_add);
|
|
_add_eid_dropdown->set_sensitive (can_add);
|
|
_add_new_mapping->set_sensitive (false);
|
|
|
|
_ok_button->set_sensitive (!_import_map.empty ());
|
|
|
|
_strip_table.show_all ();
|
|
}
|
|
|
|
void
|
|
StripImportDialog::idle_refill_import_table ()
|
|
{
|
|
Glib::signal_idle ().connect ([&] () { refill_import_table (); return false; }, Glib::PRIORITY_HIGH_IDLE + 10);
|
|
}
|
|
|
|
void
|
|
StripImportDialog::change_mapping (ArdourDropdown* dd, PBD::ID const& rid, PBD::ID const& eid, std::string const& name)
|
|
{
|
|
dd->set_text (name);
|
|
_import_map[rid] = eid;
|
|
}
|
|
|
|
void
|
|
StripImportDialog::prepare_mapping (bool ext, PBD::ID const& id, std::string const& name)
|
|
{
|
|
if (ext) {
|
|
_add_eid_dropdown->set_text (name);
|
|
_add_eid = id;
|
|
} else {
|
|
_add_rid_dropdown->set_text (name);
|
|
_add_rid = id;
|
|
}
|
|
|
|
_add_new_mapping->set_sensitive (_add_rid != PBD::ID (0) && _add_eid != PBD::ID (0));
|
|
}
|
|
|
|
void
|
|
StripImportDialog::add_mapping ()
|
|
{
|
|
assert (_add_rid != PBD::ID (0));
|
|
assert (_add_eid != PBD::ID (0));
|
|
|
|
_default_mapping = false;
|
|
_import_map[_add_rid] = _add_eid;
|
|
|
|
idle_refill_import_table ();
|
|
}
|
|
|
|
void
|
|
StripImportDialog::remove_mapping (PBD::ID const& id)
|
|
{
|
|
if (1 == _import_map.erase (id)) {
|
|
_default_mapping = false;
|
|
idle_refill_import_table ();
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::clear_mapping ()
|
|
{
|
|
_default_mapping = false;
|
|
_import_map.clear ();
|
|
idle_refill_import_table ();
|
|
}
|
|
|
|
void
|
|
StripImportDialog::import_all_strips ()
|
|
{
|
|
_default_mapping = false;
|
|
_import_map.clear ();
|
|
|
|
int64_t next_id = std::numeric_limits<uint64_t>::max () - 1 - _extern_map.size ();
|
|
for (auto& [eid, einfo] : _extern_map) {
|
|
PBD::ID next_new = PBD::ID (next_id++);
|
|
_import_map[next_new] = eid;
|
|
}
|
|
|
|
idle_refill_import_table ();
|
|
}
|
|
|
|
void
|
|
StripImportDialog::set_default_mapping (bool and_idle_update)
|
|
{
|
|
_import_map.clear ();
|
|
_default_mapping = true;
|
|
|
|
if (_match_pbd_id) {
|
|
/* try a 1:1 mapping */
|
|
for (auto& [eid, einfo] : _extern_map) {
|
|
if (_route_map.find (eid) != _route_map.end ()) {
|
|
_import_map[eid] = eid;
|
|
}
|
|
}
|
|
} else {
|
|
/* match by name */
|
|
for (auto& [eid, einfo] : _extern_map) {
|
|
// TODO consider building a reverse [pointer] map
|
|
for (auto& [rid, rinfo] : _route_map) {
|
|
#ifdef MIXBUS
|
|
if (einfo.mixbus > 0 && einfo.mixbus == rinfo.mixbus) {
|
|
_import_map[rid] = eid;
|
|
break;
|
|
}
|
|
#endif
|
|
if (einfo == rinfo) {
|
|
_import_map[rid] = eid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (and_idle_update) {
|
|
idle_refill_import_table ();
|
|
}
|
|
}
|
|
|
|
void
|
|
StripImportDialog::setup_strip_import_page ()
|
|
{
|
|
_route_map.clear ();
|
|
|
|
for (auto const& r : *_session->get_routes ()) {
|
|
#ifdef MIXBUS
|
|
_route_map.emplace (r->id (), Session::RouteImportInfo (r->name (), r->presentation_info (), c->mixbus ()));
|
|
#else
|
|
_route_map.emplace (r->id (), Session::RouteImportInfo (r->name (), r->presentation_info (), 0));
|
|
#endif
|
|
}
|
|
|
|
set_default_mapping (false);
|
|
|
|
refill_import_table ();
|
|
|
|
_clear_mapping = new ArdourButton (_("Clear Mapping"));
|
|
_reset_mapping = new ArdourButton (_match_pbd_id ? _("Reset - auto-map by ID") : _("Reset - auto-map by name"));
|
|
_import_strips = new ArdourButton (_("Import all as new tracks"));
|
|
|
|
_clear_mapping->signal_clicked.connect (mem_fun (*this, &StripImportDialog::clear_mapping));
|
|
_import_strips->signal_clicked.connect (mem_fun (*this, &StripImportDialog::import_all_strips));
|
|
_reset_mapping->signal_clicked.connect (sigc::bind (mem_fun (*this, &StripImportDialog::set_default_mapping), true));
|
|
|
|
HBox* hbox = manage (new HBox ());
|
|
hbox->set_spacing (4);
|
|
hbox->pack_start (*_clear_mapping, true, false);
|
|
hbox->pack_start (*_import_strips, true, false);
|
|
hbox->pack_start (*_reset_mapping, true, false);
|
|
|
|
VBox* vbox = manage (new VBox ());
|
|
vbox->pack_start (_strip_table, false, false, 4);
|
|
|
|
_strip_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
|
|
_strip_scroller.add (*vbox);
|
|
|
|
_page_strip.set_spacing (4);
|
|
_page_strip.pack_start (_strip_scroller);
|
|
_page_strip.pack_end (*hbox, false, false, 4);
|
|
_page_strip.show_all ();
|
|
|
|
_ok_button->set_sensitive (true); // XXX
|
|
}
|
|
|
|
void
|
|
StripImportDialog::ok_activated ()
|
|
{
|
|
_session->import_route_state (_path, _import_map);
|
|
ArdourDialog::on_response (RESPONSE_ACCEPT);
|
|
}
|