Implement Strip Import UI
This commit is contained in:
@@ -16,22 +16,660 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "strip_import_dialog.h"
|
||||
#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 Presets"));
|
||||
|
||||
_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 Presets"));
|
||||
|
||||
_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 */
|
||||
|
||||
/* Refill table */
|
||||
int r = 1;
|
||||
for (auto& [rid, eid] : _import_map) {
|
||||
++r;
|
||||
if (_route_map.find (rid) != _route_map.end ()) {
|
||||
l = manage (new Label (_route_map[rid], 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, ename] : _extern_map) {
|
||||
dd->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (ename), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::change_mapping), dd, rid, eid, ename)));
|
||||
}
|
||||
dd->set_text (_extern_map[eid]);
|
||||
_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 colums 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, rname] : _route_map) {
|
||||
if (_import_map.find (rid) != _import_map.end ()) {
|
||||
continue;
|
||||
}
|
||||
_add_rid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (rname), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, rid, rname)));
|
||||
sizing_texts.push_back (rname);
|
||||
}
|
||||
|
||||
_add_eid_dropdown = manage (new ArdourWidgets::ArdourDropdown ());
|
||||
for (auto& [eid, ename] : _extern_map) {
|
||||
_add_eid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (ename), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), true, eid, ename)));
|
||||
sizing_texts.push_back (ename);
|
||||
}
|
||||
|
||||
_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, ename] : _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, ename] : _extern_map) {
|
||||
if (_route_map.find (eid) != _route_map.end ()) {
|
||||
_import_map[eid] = eid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* match by name */
|
||||
for (auto& [eid, ename] : _extern_map) {
|
||||
// TODO consider building a reverse [pointer] map
|
||||
for (auto& [rid, rname] : _route_map) {
|
||||
if (ename == rname) {
|
||||
_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 ()) {
|
||||
_route_map[r->id ()] = r->name ();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -17,12 +17,21 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include <ytkmm/box.h>
|
||||
#include <ytkmm/filechooserwidget.h>
|
||||
#include <ytkmm/liststore.h>
|
||||
#include <ytkmm/notebook.h>
|
||||
#include <ytkmm/scrolledwindow.h>
|
||||
#include <ytkmm/table.h>
|
||||
#include <ytkmm/treestore.h>
|
||||
#include <ytkmm/treeview.h>
|
||||
|
||||
#include "ardour/search_paths.h"
|
||||
#include "pbd/id.h"
|
||||
|
||||
#include "ardour/template_utils.h"
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
namespace ARDOUR
|
||||
@@ -30,9 +39,103 @@ namespace ARDOUR
|
||||
class Session;
|
||||
}
|
||||
|
||||
class StripImportDialog : public ArdourDialog, public PBD::ScopedConnectionList
|
||||
namespace ArdourWidgets
|
||||
{
|
||||
class ArdourButton;
|
||||
class ArdourDropdown;
|
||||
}
|
||||
|
||||
class StripImportDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
StripImportDialog (ARDOUR::Session*);
|
||||
~StripImportDialog ();
|
||||
|
||||
private:
|
||||
enum SelectionType {
|
||||
Template,
|
||||
RouteState,
|
||||
Snapshot
|
||||
};
|
||||
|
||||
void page_changed (GtkNotebookPage*, guint);
|
||||
void setup_file_page ();
|
||||
void file_selection_changed ();
|
||||
void treeview_selection_changed (Gtk::TreeView*, SelectionType);
|
||||
void parse_route_state (std::string const&);
|
||||
void setup_model (Glib::RefPtr<Gtk::ListStore>, std::vector<ARDOUR::TemplateInfo> const&);
|
||||
void find_presets (PBD::Searchpath const&, std::vector<ARDOUR::TemplateInfo>&);
|
||||
|
||||
void setup_strip_import_page ();
|
||||
void refill_import_table ();
|
||||
void idle_refill_import_table ();
|
||||
void maybe_switch_to_import_page ();
|
||||
void add_mapping ();
|
||||
void change_mapping (ArdourWidgets::ArdourDropdown*, PBD::ID const&, PBD::ID const&, std::string const&);
|
||||
void prepare_mapping (bool, PBD::ID const&, std::string const&);
|
||||
void remove_mapping (PBD::ID const&);
|
||||
void clear_mapping ();
|
||||
void import_all_strips ();
|
||||
void set_default_mapping (bool and_idle_update);
|
||||
void update_sensitivity_ok ();
|
||||
void ok_activated ();
|
||||
|
||||
struct SessionTemplateColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
SessionTemplateColumns ()
|
||||
{
|
||||
add (name);
|
||||
add (path);
|
||||
}
|
||||
|
||||
Gtk::TreeModelColumn<std::string> name;
|
||||
Gtk::TreeModelColumn<std::string> path;
|
||||
};
|
||||
|
||||
SessionTemplateColumns _columns;
|
||||
Glib::RefPtr<Gtk::TreeStore> _recent_model;
|
||||
Glib::RefPtr<Gtk::ListStore> _template_model;
|
||||
Glib::RefPtr<Gtk::ListStore> _local_pset_model;
|
||||
Glib::RefPtr<Gtk::ListStore> _global_pset_model;
|
||||
|
||||
std::map<guint, Gtk::TreeView*> _notebook_content;
|
||||
std::map<guint, SelectionType> _notebook_type;
|
||||
|
||||
Gtk::VBox _page_file;
|
||||
Gtk::VBox _page_strip;
|
||||
|
||||
Gtk::Notebook _notebook;
|
||||
Gtk::FileChooserWidget _chooser;
|
||||
Gtk::Button* _open_button;
|
||||
Gtk::Button* _ok_button;
|
||||
Gtk::Label _info_text;
|
||||
Gtk::ScrolledWindow _recent_scroller;
|
||||
Gtk::TreeView _recent_treeview;
|
||||
Gtk::ScrolledWindow _template_scroller;
|
||||
Gtk::TreeView _template_treeview;
|
||||
Gtk::ScrolledWindow _local_pset_scroller;
|
||||
Gtk::TreeView _local_pset_treeview;
|
||||
Gtk::ScrolledWindow _global_pset_scroller;
|
||||
Gtk::TreeView _global_pset_treeview;
|
||||
|
||||
Gtk::Table _strip_table;
|
||||
Gtk::ScrolledWindow _strip_scroller;
|
||||
ArdourWidgets::ArdourDropdown* _add_rid_dropdown;
|
||||
ArdourWidgets::ArdourDropdown* _add_eid_dropdown;
|
||||
ArdourWidgets::ArdourButton* _add_new_mapping;
|
||||
ArdourWidgets::ArdourButton* _clear_mapping;
|
||||
ArdourWidgets::ArdourButton* _reset_mapping;
|
||||
ArdourWidgets::ArdourButton* _import_strips;
|
||||
|
||||
bool _match_pbd_id;
|
||||
std::string _path;
|
||||
std::map<PBD::ID, std::string> _extern_map;
|
||||
std::map<PBD::ID, std::string> _route_map;
|
||||
std::map<PBD::ID, PBD::ID> _import_map;
|
||||
|
||||
PBD::ID _add_rid;
|
||||
PBD::ID _add_eid;
|
||||
bool _default_mapping;
|
||||
|
||||
sigc::connection _notebook_connection;
|
||||
sigc::connection _chooser_connection;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user