From b5a57cc78c92b1d887b7e8de040d8663a9ba187e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 17 Sep 2008 12:56:00 +0000 Subject: new files from sakari, missed last time git-svn-id: svn://localhost/ardour2/branches/3.0@3738 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/export_channel_selector.cc | 427 ++++++++++++++ gtk2_ardour/export_channel_selector.h | 181 ++++++ gtk2_ardour/export_filename_selector.cc | 303 ++++++++++ gtk2_ardour/export_filename_selector.h | 120 ++++ gtk2_ardour/export_format_dialog.cc | 953 ++++++++++++++++++++++++++++++++ gtk2_ardour/export_format_dialog.h | 308 +++++++++++ gtk2_ardour/export_format_selector.cc | 169 ++++++ gtk2_ardour/export_format_selector.h | 91 +++ gtk2_ardour/export_main_dialog.cc | 640 +++++++++++++++++++++ gtk2_ardour/export_main_dialog.h | 234 ++++++++ gtk2_ardour/export_multiplicator.cc | 330 +++++++++++ gtk2_ardour/export_multiplicator.h | 121 ++++ gtk2_ardour/export_timespan_selector.cc | 394 +++++++++++++ gtk2_ardour/export_timespan_selector.h | 132 +++++ gtk2_ardour/session_metadata_dialog.cc | 738 +++++++++++++++++++++++++ gtk2_ardour/session_metadata_dialog.h | 276 +++++++++ gtk2_ardour/time_axis_view.cc | 11 +- 17 files changed, 5425 insertions(+), 3 deletions(-) create mode 100644 gtk2_ardour/export_channel_selector.cc create mode 100644 gtk2_ardour/export_channel_selector.h create mode 100644 gtk2_ardour/export_filename_selector.cc create mode 100644 gtk2_ardour/export_filename_selector.h create mode 100644 gtk2_ardour/export_format_dialog.cc create mode 100644 gtk2_ardour/export_format_dialog.h create mode 100644 gtk2_ardour/export_format_selector.cc create mode 100644 gtk2_ardour/export_format_selector.h create mode 100644 gtk2_ardour/export_main_dialog.cc create mode 100644 gtk2_ardour/export_main_dialog.h create mode 100644 gtk2_ardour/export_multiplicator.cc create mode 100644 gtk2_ardour/export_multiplicator.h create mode 100644 gtk2_ardour/export_timespan_selector.cc create mode 100644 gtk2_ardour/export_timespan_selector.h create mode 100644 gtk2_ardour/session_metadata_dialog.cc create mode 100644 gtk2_ardour/session_metadata_dialog.h (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/export_channel_selector.cc b/gtk2_ardour/export_channel_selector.cc new file mode 100644 index 0000000000..41ecec9094 --- /dev/null +++ b/gtk2_ardour/export_channel_selector.cc @@ -0,0 +1,427 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_channel_selector.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; + +ExportChannelSelector::ExportChannelSelector () : + channels_label (_("Channels:"), Gtk::ALIGN_LEFT), + split_checkbox (_("Split to mono files")), + max_channels (20), + channel_view (max_channels) +{ + + channels_hbox.pack_start (channels_label, false, false, 0); + channels_hbox.pack_end (channels_spinbutton, false, false, 0); + + channels_vbox.pack_start (channels_hbox, false, false, 0); + channels_vbox.pack_start (split_checkbox, false, false, 6); + + channel_alignment.add (channel_scroller); + channel_alignment.set_padding (0, 0, 12, 0); + channel_scroller.add (channel_view); + channel_scroller.set_size_request (-1, 130); + channel_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + + pack_start (channels_vbox, false, false, 0); + pack_start (channel_alignment, true, true, 0); + + /* Channels spinbutton */ + + channels_spinbutton.set_digits (0); + channels_spinbutton.set_increments (1, 2); + channels_spinbutton.set_range (1, max_channels); + channels_spinbutton.set_value (2); + + channels_spinbutton.signal_value_changed().connect (sigc::mem_fun (*this, &ExportChannelSelector::update_channel_count)); + + /* Other signals */ + + split_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportChannelSelector::update_split_state)); + channel_view.CriticalSelectionChanged.connect (CriticalSelectionChanged.make_slot()); + + /* Finalize */ + + show_all_children (); + +} + +ExportChannelSelector::~ExportChannelSelector () +{ +// if (session) { +// session->add_instant_xml (get_state(), false); +// } +} + +void +ExportChannelSelector::set_state (ARDOUR::ExportProfileManager::ChannelConfigStatePtr const state_, ARDOUR::Session * session_) +{ + state = state_; + session = session_; + + split_checkbox.set_active (state->config->get_split()); + channels_spinbutton.set_value (state->config->get_n_chans()); + + fill_route_list (); + channel_view.set_config (state->config); +} + +void +ExportChannelSelector::fill_route_list () +{ + channel_view.clear_routes (); + Session::RouteList routes = *session->get_routes(); + + /* Add master bus and then everything else */ + + ARDOUR::IO * master = session->master_out().get(); + channel_view.add_route (master); + + for (Session::RouteList::iterator it = routes.begin(); it != routes.end(); ++it) { + if (it->get() == master) { + continue; + } + channel_view.add_route (it->get()); + } + + update_channel_count (); +} + +void +ExportChannelSelector::update_channel_count () +{ + uint32_t chans = static_cast (channels_spinbutton.get_value()); + channel_view.set_channel_count (chans); + CriticalSelectionChanged(); +} + +void +ExportChannelSelector::update_split_state () +{ + state->config->set_split (split_checkbox.get_active()); + CriticalSelectionChanged(); +} + +void +ExportChannelSelector::RouteCols::add_channels (uint32_t chans) +{ + while (chans > 0) { + channels.push_back (Channel (*this)); + ++n_channels; + --chans; + } +} + +ExportChannelSelector::RouteCols::Channel & +ExportChannelSelector::RouteCols::get_channel (uint32_t channel) +{ + if (channel > n_channels) { + std::cout << "Invalid channel cout for get_channel!" << std::endl; + } + + std::list::iterator it = channels.begin(); + + while (channel > 1) { // Channel count starts from one! + ++it; + --channel; + } + + return *it; +} + +ExportChannelSelector::ChannelTreeView::ChannelTreeView (uint32_t max_channels) : + n_channels (0) +{ + /* Main columns */ + + route_cols.add_channels (max_channels); + + route_list = Gtk::ListStore::create(route_cols); + set_model (route_list); + + /* Add column with toggle and text */ + + append_column_editable (_("Bus or Track"), route_cols.selected); + + Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); + text_renderer->property_editable() = false; + + Gtk::TreeView::Column* column = get_column (0); + column->pack_start (*text_renderer); + column->add_attribute (text_renderer->property_text(), route_cols.name); + + Gtk::CellRendererToggle *toggle = dynamic_cast(get_column_cell_renderer (0)); + toggle->signal_toggled().connect (mem_fun (*this, &ExportChannelSelector::ChannelTreeView::update_toggle_selection)); + + static_columns = get_columns().size(); +} + +void +ExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c) +{ + /* TODO Without the following line, the state might get reset. + * Pointing to the same address does not mean the state of the configuration hasn't changed. + * In the current code this is safe, but the actual cause of the problem would be good to fix + */ + + if (config == c) { return; } + config = c; + + uint32_t i = 1; + ExportChannelConfiguration::ChannelList chan_list = config->get_channels(); + for (ExportChannelConfiguration::ChannelList::iterator c_it = chan_list.begin(); c_it != chan_list.end(); ++c_it) { + + for (Gtk::ListStore::Children::iterator r_it = route_list->children().begin(); r_it != route_list->children().end(); ++r_it) { + + Glib::RefPtr port_list = r_it->get_value (route_cols.port_list_col); + std::set route_ports; + std::set intersection; + std::map port_labels; + + for (Gtk::ListStore::Children::const_iterator p_it = port_list->children().begin(); p_it != port_list->children().end(); ++p_it) { + route_ports.insert ((*p_it)->get_value (route_cols.port_cols.port)); + port_labels.insert (std::pair ((*p_it)->get_value (route_cols.port_cols.port), + (*p_it)->get_value (route_cols.port_cols.label))); + } + + std::set_intersection ((*c_it)->begin(), (*c_it)->end(), + route_ports.begin(), route_ports.end(), + std::insert_iterator > (intersection, intersection.begin())); + + intersection.erase (0); // Remove "none" selection + + if (intersection.empty()) { + continue; + } + + if (!r_it->get_value (route_cols.selected)) { + r_it->set_value (route_cols.selected, true); + + /* Set previous channels (if any) to none */ + + for (uint32_t chn = 1; chn < i; ++chn) { + r_it->set_value (route_cols.get_channel (chn).port, (AudioPort *) 0); + r_it->set_value (route_cols.get_channel (chn).label, ustring ("(none)")); + } + } + + AudioPort * port = *intersection.begin(); + std::map::iterator label_it = port_labels.find (port); + ustring label = label_it != port_labels.end() ? label_it->second : "error"; + + r_it->set_value (route_cols.get_channel (i).port, port); + r_it->set_value (route_cols.get_channel (i).label, label); + } + + ++i; + } +} + +void +ExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * route) +{ + Gtk::TreeModel::iterator iter = route_list->append(); + Gtk::TreeModel::Row row = *iter; + + row[route_cols.selected] = false; + row[route_cols.name] = route->name(); + row[route_cols.io] = route; + + /* Initialize port list */ + + Glib::RefPtr port_list = Gtk::ListStore::create (route_cols.port_cols); + row[route_cols.port_list_col] = port_list; + + uint32_t outs = route->n_outputs().n_audio(); + for (uint32_t i = 0; i < outs; ++i) { + iter = port_list->append(); + row = *iter; + + row[route_cols.port_cols.selected] = false; + row[route_cols.port_cols.port] = route->audio_output (i); + + std::ostringstream oss; + oss << "Out-" << (i + 1); + + row[route_cols.port_cols.label] = oss.str(); + } + + iter = port_list->append(); + row = *iter; + + row[route_cols.port_cols.selected] = false; + row[route_cols.port_cols.port] = 0; + row[route_cols.port_cols.label] = "(none)"; + +} + +void +ExportChannelSelector::ChannelTreeView::set_channel_count (uint32_t channels) +{ + int offset = channels - n_channels; + + while (offset > 0) { + ++n_channels; + + std::ostringstream oss; + oss << n_channels; + + /* New column */ + + Gtk::TreeView::Column* column = Gtk::manage (new Gtk::TreeView::Column (oss.str())); + + Gtk::CellRendererCombo* combo_renderer = Gtk::manage (new Gtk::CellRendererCombo); + combo_renderer->property_text_column() = 2; + column->pack_start (*combo_renderer); + + append_column (*column); + + column->add_attribute (combo_renderer->property_text(), route_cols.get_channel(n_channels).label); + column->add_attribute (combo_renderer->property_model(), route_cols.port_list_col); + column->add_attribute (combo_renderer->property_editable(), route_cols.selected); + + combo_renderer->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &ExportChannelSelector::ChannelTreeView::update_selection_text), n_channels)); + + /* put data into view */ + + for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) { + Glib::ustring label = it->get_value(route_cols.selected) ? "(none)" : ""; + it->set_value (route_cols.get_channel (n_channels).label, label); + it->set_value (route_cols.get_channel (n_channels).port, (AudioPort *) 0); + } + + /* set column width */ + + get_column (static_columns + n_channels - 1)->set_min_width (80); + + --offset; + } + + while (offset < 0) { + --n_channels; + + remove_column (*get_column (n_channels + static_columns)); + + ++offset; + } + + update_config (); +} + +void +ExportChannelSelector::ChannelTreeView::update_config () +{ + + if (!config) { return; } + + config->clear_channels(); + + for (uint32_t i = 1; i <= n_channels; ++i) { + + boost::shared_ptr channel (new ExportChannel ()); + + for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) { + Gtk::TreeModel::Row row = *it; + + if (!row[route_cols.selected]) { + continue; + } + + AudioPort * port = row[route_cols.get_channel (i).port]; + if (port) { + channel->add_port (port); + } + } + + config->register_channel (channel); + } + + CriticalSelectionChanged (); +} + +void +ExportChannelSelector::ChannelTreeView::update_toggle_selection (Glib::ustring const & path) +{ + Gtk::TreeModel::iterator iter = get_model ()->get_iter (path); + bool selected = iter->get_value (route_cols.selected); + + for (uint32_t i = 1; i <= n_channels; ++i) { + + if (!selected) { + iter->set_value (route_cols.get_channel (i).label, Glib::ustring ("")); + continue; + } + + iter->set_value (route_cols.get_channel (i).label, Glib::ustring("(none)")); + iter->set_value (route_cols.get_channel (i).port, (AudioPort *) 0); + + Glib::RefPtr port_list = iter->get_value (route_cols.port_list_col); + Gtk::ListStore::Children::iterator port_it; + uint32_t port_number = 1; + + for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) { + if (port_number == i) { + iter->set_value (route_cols.get_channel (i).label, (Glib::ustring) (*port_it)->get_value (route_cols.port_cols.label)); + iter->set_value (route_cols.get_channel (i).port, (AudioPort *) (*port_it)->get_value (route_cols.port_cols.port)); + } + + ++port_number; + } + } + + update_config (); +} + +void +ExportChannelSelector::ChannelTreeView::update_selection_text (Glib::ustring const & path, Glib::ustring const & new_text, uint32_t channel) +{ + Gtk::TreeModel::iterator iter = get_model ()->get_iter (path); + iter->set_value (route_cols.get_channel (channel).label, new_text); + + Glib::RefPtr port_list = iter->get_value (route_cols.port_list_col); + Gtk::ListStore::Children::iterator port_it; + + for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) { + Glib::ustring label = port_it->get_value (route_cols.port_cols.label); + if (label == new_text) { + iter->set_value (route_cols.get_channel (channel).port, (AudioPort *) (*port_it)[route_cols.port_cols.port]); + } + } + + update_config (); +} diff --git a/gtk2_ardour/export_channel_selector.h b/gtk2_ardour/export_channel_selector.h new file mode 100644 index 0000000000..0faf652bd8 --- /dev/null +++ b/gtk2_ardour/export_channel_selector.h @@ -0,0 +1,181 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_channel_selector_h__ +#define __export_channel_selector_h__ + +#include + +#include + +#include +#include +#include + +namespace ARDOUR { + class Session; + class ExportChannel; + class ExportChannelConfiguration; + class ExportHandler; + class AudioPort; + class IO; +} + +class XMLNode; + +/// +class ExportChannelSelector : public Gtk::HBox { + private: + + typedef boost::shared_ptr ChannelConfigPtr; + + typedef boost::shared_ptr HandlerPtr; + + public: + + ExportChannelSelector (); + ~ExportChannelSelector (); + + void set_state (ARDOUR::ExportProfileManager::ChannelConfigStatePtr const state_, ARDOUR::Session * session_); + + sigc::signal CriticalSelectionChanged; + + private: + + void fill_route_list (); + void update_channel_count (); + void update_split_state (); + + typedef boost::shared_ptr ChannelPtr; + typedef std::list CahnnelList; + + ARDOUR::Session * session; + ARDOUR::ExportProfileManager::ChannelConfigStatePtr state; + + /*** GUI stuff ***/ + + Gtk::VBox channels_vbox; + Gtk::HBox channels_hbox; + + Gtk::Label channels_label; + Gtk::SpinButton channels_spinbutton; + Gtk::CheckButton split_checkbox; + + /* Column record for channel selector view */ + + class RouteCols : public Gtk::TreeModelColumnRecord + { + public: + + struct Channel; + + RouteCols () : n_channels (0) + { add (selected); add (name); add (io); add (port_list_col); } + + void add_channels (uint32_t chans); + uint32_t n_channels; + + /* Channel count starts from one! */ + + Channel & get_channel (uint32_t channel); + + /* Static columns */ + + Gtk::TreeModelColumn selected; + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn io; + + /* Combo list column (shared by all channels) */ + + typedef Gtk::TreeModelColumn > ComboCol; + ComboCol port_list_col; + + /* Channel struct, that represents the selected port and it's name */ + + struct Channel { + public: + Channel (RouteCols & cols) { cols.add (port); cols.add (label); } + + Gtk::TreeModelColumn port; + Gtk::TreeModelColumn label; + }; + std::list channels; + + /* List of available ports + * Note: We need only one list of selectable ports per route, + * so the list is kept in the column record + */ + + /* Column record for selecting ports for a channel from a route */ + + class PortCols : public Gtk::TreeModel::ColumnRecord + { + public: + PortCols () { add (selected); add(port); add(label); } + + Gtk::TreeModelColumn selected; // not used ATM + Gtk::TreeModelColumn port; + Gtk::TreeModelColumn label; + }; + PortCols port_cols; + }; + + /* Channels view */ + + class ChannelTreeView : public Gtk::TreeView { + public: + + ChannelTreeView (uint32_t max_channels); + void set_config (ChannelConfigPtr c); + + /* Routes have to be added before adding channels */ + + void clear_routes () { route_list->clear (); } + void add_route (ARDOUR::IO * route); + void set_channel_count (uint32_t channels); + + sigc::signal CriticalSelectionChanged; + + private: + + ChannelConfigPtr config; + void update_config (); + + /* Signal handlers for selections changes in the view */ + + void update_toggle_selection (Glib::ustring const & path); + void update_selection_text (Glib::ustring const & path, Glib::ustring const & new_text, uint32_t channel); + + RouteCols route_cols; + Glib::RefPtr route_list; + + uint32_t static_columns; + uint32_t n_channels; + }; + + uint32_t max_channels; + + Gtk::ScrolledWindow channel_scroller; + Gtk::Alignment channel_alignment; + ChannelTreeView channel_view; + +}; + +#endif /* __export_channel_selector_h__ */ diff --git a/gtk2_ardour/export_filename_selector.cc b/gtk2_ardour/export_filename_selector.cc new file mode 100644 index 0000000000..186ff69a80 --- /dev/null +++ b/gtk2_ardour/export_filename_selector.cc @@ -0,0 +1,303 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_filename_selector.h" + +#include +#include +#include + +#include "i18n.h" + +using namespace ARDOUR; + +ExportFilenameSelector::ExportFilenameSelector () : + session (0), + + include_label (_("Include in Filename(s):"), Gtk::ALIGN_LEFT), + + label_label (_("Label:"), Gtk::ALIGN_LEFT), + session_checkbox (_("Session Name")), + revision_checkbox (_("Revision:")), + + path_label (_("Folder:"), Gtk::ALIGN_LEFT), + browse_button (_("Browse")) +{ + pack_start (include_label, false, false, 6); + pack_start (include_hbox, false, false, 0); + pack_start (path_hbox, false, false, 12); + + include_hbox.pack_start (label_label, false, false, 3); + include_hbox.pack_start (label_entry, false, false, 3); + include_hbox.pack_start (session_checkbox, false, false, 3); + include_hbox.pack_start (date_format_combo, false, false, 3); + include_hbox.pack_start (time_format_combo, false, false, 3); + include_hbox.pack_start (revision_checkbox, false, false, 3); + include_hbox.pack_start (revision_spinbutton, false, false, 3); + + path_hbox.pack_start (path_label, false, false, 3); + path_hbox.pack_start (path_entry, true, true, 3); + path_hbox.pack_start (browse_button, false, false, 3); + + label_sizegroup = Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL); + label_sizegroup->add_widget (label_label); + label_sizegroup->add_widget (path_label); + + /* Date */ + + date_format_list = Gtk::ListStore::create (date_format_cols); + date_format_combo.set_model (date_format_list); + date_format_combo.pack_start (date_format_cols.label); + + date_format_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportFilenameSelector::change_date_format)); + + /* Time */ + + time_format_list = Gtk::ListStore::create (time_format_cols); + time_format_combo.set_model (time_format_list); + time_format_combo.pack_start (time_format_cols.label); + + time_format_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportFilenameSelector::change_time_format)); + + /* Revision */ + + revision_spinbutton.set_digits (0); + revision_spinbutton.set_increments (1, 10); + revision_spinbutton.set_range (1, 1000); + revision_spinbutton.set_sensitive (false); + + /* Signals */ + + label_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportFilenameSelector::update_label)); + path_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportFilenameSelector::update_folder)); + + session_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportFilenameSelector::change_session_selection)); + + revision_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportFilenameSelector::change_revision_selection)); + revision_spinbutton.signal_value_changed().connect (sigc::mem_fun (*this, &ExportFilenameSelector::change_revision_value)); + + browse_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportFilenameSelector::open_browse_dialog)); +} + +ExportFilenameSelector::~ExportFilenameSelector () +{ + +} + +void +ExportFilenameSelector::load_state () +{ + if (!filename) { + return; + } + + label_entry.set_text (filename->include_label ? filename->get_label() : ""); + session_checkbox.set_active (filename->include_session); + revision_checkbox.set_active (filename->include_revision); + revision_spinbutton.set_value (filename->get_revision()); + path_entry.set_text (filename->get_folder()); + + Gtk::TreeModel::Children::iterator it; + + for (it = date_format_list->children().begin(); it != date_format_list->children().end(); ++it) { + if (it->get_value (date_format_cols.format) == filename->get_date_format()) { + date_format_combo.set_active (it); + } + } + + for (it = time_format_list->children().begin(); it != time_format_list->children().end(); ++it) { + if (it->get_value (time_format_cols.format) == filename->get_time_format()) { + time_format_combo.set_active (it); + } + } +} + +void +ExportFilenameSelector::set_state (ARDOUR::ExportProfileManager::FilenameStatePtr state_, ARDOUR::Session * session_) +{ + session = session_; + + filename = state_->filename; + + /* Fill combo boxes */ + + Gtk::TreeModel::iterator iter; + Gtk::TreeModel::Row row; + + /* Dates */ + + date_format_list->clear(); + + iter = date_format_list->append(); + row = *iter; + row[date_format_cols.format] = ExportFilename::D_None; + row[date_format_cols.label] = filename->get_date_format_str (ExportFilename::D_None); + + iter = date_format_list->append(); + row = *iter; + row[date_format_cols.format] = ExportFilename::D_ISO; + row[date_format_cols.label] = filename->get_date_format_str (ExportFilename::D_ISO); + + iter = date_format_list->append(); + row = *iter; + row[date_format_cols.format] = ExportFilename::D_ISOShortY; + row[date_format_cols.label] = filename->get_date_format_str (ExportFilename::D_ISOShortY); + + iter = date_format_list->append(); + row = *iter; + row[date_format_cols.format] = ExportFilename::D_BE; + row[date_format_cols.label] = filename->get_date_format_str (ExportFilename::D_BE); + + iter = date_format_list->append(); + row = *iter; + row[date_format_cols.format] = ExportFilename::D_BEShortY; + row[date_format_cols.label] = filename->get_date_format_str (ExportFilename::D_BEShortY); + + /* Times */ + + time_format_list->clear(); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportFilename::T_None; + row[time_format_cols.label] = filename->get_time_format_str (ExportFilename::T_None); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportFilename::T_NoDelim; + row[time_format_cols.label] = filename->get_time_format_str (ExportFilename::T_NoDelim); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportFilename::T_Delim; + row[time_format_cols.label] = filename->get_time_format_str (ExportFilename::T_Delim); + + /* Load state */ + + load_state(); + +} + +void +ExportFilenameSelector::update_label () +{ + if (!filename) { + return; + } + + filename->set_label (label_entry.get_text()); + + filename->include_label = !label_entry.get_text().empty(); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::update_folder () +{ + if (!filename) { + return; + } + + filename->set_folder (path_entry.get_text()); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::change_date_format () +{ + if (!filename) { + return; + } + + DateFormat format = date_format_combo.get_active()->get_value (date_format_cols.format); + filename->set_date_format (format); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::change_time_format () +{ + if (!filename) { + return; + } + + TimeFormat format = time_format_combo.get_active()->get_value (time_format_cols.format); + filename->set_time_format (format); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::change_session_selection () +{ + if (!filename) { + return; + } + + filename->include_session = session_checkbox.get_active(); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::change_revision_selection () +{ + if (!filename) { + return; + } + + bool selected = revision_checkbox.get_active(); + filename->include_revision = selected; + + revision_spinbutton.set_sensitive (selected); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::change_revision_value () +{ + if (!filename) { + return; + } + + filename->set_revision ((uint32_t) revision_spinbutton.get_value_as_int()); + CriticalSelectionChanged(); +} + +void +ExportFilenameSelector::open_browse_dialog () +{ + Gtk::FileChooserDialog dialog(_("Choose export folder"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + //dialog.set_transient_for(*this); + dialog.set_filename (path_entry.get_text()); + + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + + int result = dialog.run(); + + if (result == Gtk::RESPONSE_OK) { + Glib::ustring filename = dialog.get_filename(); + + if (filename.length()) { + path_entry.set_text (filename); + } + } + + CriticalSelectionChanged(); +} diff --git a/gtk2_ardour/export_filename_selector.h b/gtk2_ardour/export_filename_selector.h new file mode 100644 index 0000000000..c21435bb57 --- /dev/null +++ b/gtk2_ardour/export_filename_selector.h @@ -0,0 +1,120 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_filename_selector_h__ +#define __export_filename_selector_h__ + +#include + +#include +#include + +namespace ARDOUR { + class Session; +} + +/// +class ExportFilenameSelector : public Gtk::VBox { + public: + typedef boost::shared_ptr FilenamePtr; + + ExportFilenameSelector (); + ~ExportFilenameSelector (); + + void set_state (ARDOUR::ExportProfileManager::FilenameStatePtr state_, ARDOUR::Session * session_); + + /* Compatibility with other elements */ + + sigc::signal CriticalSelectionChanged; + + private: + + void load_state (); + + void update_label (); + void update_folder (); + + void change_date_format (); + void change_time_format (); + + void change_session_selection (); + void change_revision_selection (); + void change_revision_value (); + + void open_browse_dialog (); + + ARDOUR::Session * session; + boost::shared_ptr filename; + + Glib::RefPtr label_sizegroup; + + Gtk::Label include_label; + + Gtk::HBox include_hbox; + + Gtk::Label label_label; + Gtk::Entry label_entry; + + Gtk::CheckButton session_checkbox; + + Gtk::CheckButton revision_checkbox; + Gtk::SpinButton revision_spinbutton; + + Gtk::HBox path_hbox; + + Gtk::Label path_label; + Gtk::Entry path_entry; + Gtk::Button browse_button; + + /* Date combo */ + + typedef ARDOUR::ExportFilename::DateFormat DateFormat; + + struct DateFormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn format; + Gtk::TreeModelColumn label; + + DateFormatCols () { add(format); add(label); } + }; + DateFormatCols date_format_cols; + Glib::RefPtr date_format_list; + Gtk::ComboBox date_format_combo; + + /* Time combo */ + + typedef ARDOUR::ExportFilename::TimeFormat TimeFormat; + + struct TimeFormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn format; + Gtk::TreeModelColumn label; + + TimeFormatCols () { add(format); add(label); } + }; + TimeFormatCols time_format_cols; + Glib::RefPtr time_format_list; + Gtk::ComboBox time_format_combo; + +}; + +#endif /* __export_filename_selector_h__ */ diff --git a/gtk2_ardour/export_format_dialog.cc b/gtk2_ardour/export_format_dialog.cc new file mode 100644 index 0000000000..f123c9cbbb --- /dev/null +++ b/gtk2_ardour/export_format_dialog.cc @@ -0,0 +1,953 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_format_dialog.h" + +#include +#include + +#include "i18n.h" + +using namespace ARDOUR; + +ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) : + ArdourDialog (new_dialog ? _("New export format profile") : _("Edit export format profile")), + format (format), + manager (format), + original_state (format->get_state()), + + applying_changes_from_engine (0), + + name_label (_("Label: "), Gtk::ALIGN_LEFT), + + normalize_checkbox (_("Normalize to:")), + normalize_adjustment (0.00, -90.00, 0.00, 0.1, 0.2), + normalize_db_label (_("dBFS"), Gtk::ALIGN_LEFT), + + silence_table (2, 4), + trim_start_checkbox (_("Trim silence at start")), + silence_start_checkbox (_("Add silence at start:")), + silence_start_clock ("silence_start", true, "PreRollClock", true, true), + + trim_end_checkbox (_("Trim silence at end")), + silence_end_checkbox (_("Add silence at end:")), + silence_end_clock ("silence_end", true, "PreRollClock", true, true), + + format_table (3, 4), + compatibility_label (_("Compatibility"), Gtk::ALIGN_LEFT), + quality_label (_("Quality"), Gtk::ALIGN_LEFT), + format_label (_("File format"), Gtk::ALIGN_LEFT), + sample_rate_label (_("Sample rate"), Gtk::ALIGN_LEFT), + src_quality_label (_("Sample rate conversion quality:"), Gtk::ALIGN_RIGHT), + + encoding_options_label (_(""), Gtk::ALIGN_LEFT), + + /* Changing encoding options from here on */ + + sample_format_label (_("Sample Format"), Gtk::ALIGN_LEFT), + dither_label (_("Dithering"), Gtk::ALIGN_LEFT), + + tag_checkbox (_("Tag file with session's metadata")) +{ + + /* Pack containers in dialog */ + + get_vbox()->pack_start (name_hbox, false, false, 0); + get_vbox()->pack_start (silence_table, false, false, 6); + get_vbox()->pack_start (format_table, false, false, 6); + get_vbox()->pack_start (encoding_options_vbox, false, false, 0); + + /* Name, new and remove */ + + name_hbox.pack_start (name_label, false, false, 0); + name_hbox.pack_start (name_entry, true, true, 0); + + /* Normalize */ + + normalize_hbox.pack_start (normalize_checkbox, false, false, 0); + normalize_hbox.pack_start (normalize_spinbutton, false, false, 6); + normalize_hbox.pack_start (normalize_db_label, false, false, 0); + + normalize_spinbutton.configure (normalize_adjustment, 0.1, 2); + + /* Silence */ + + silence_table.set_row_spacings (6); + silence_table.set_col_spacings (12); + + silence_table.attach (normalize_hbox, 0, 3, 0, 1); + + silence_table.attach (trim_start_checkbox, 0, 1, 1, 2); + silence_table.attach (silence_start_checkbox, 1, 2, 1, 2); + silence_table.attach (silence_start_clock, 2, 3, 1, 2); + + silence_table.attach (trim_end_checkbox, 0, 1, 2, 3); + silence_table.attach (silence_end_checkbox, 1, 2, 2, 3); + silence_table.attach (silence_end_clock, 2, 3, 2, 3); + + /* Format table */ + + init_format_table(); + + /* Encoding options */ + + init_encoding_option_widgets(); + + encoding_options_table.set_spacings (1); + + encoding_options_vbox.pack_start (encoding_options_label, false, false, 0); + encoding_options_vbox.pack_start (encoding_options_table, false, false, 12); + + Pango::AttrList bold; + Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD); + bold.insert (b); + encoding_options_label.set_attributes (bold); + + /* Buttons */ + + revert_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + revert_button->signal_clicked().connect (mem_fun(*this, &ExportFormatDialog::revert)); + close_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_APPLY); + close_button->set_sensitive (false); + close_button->signal_clicked().connect (mem_fun (*this, &ExportFormatDialog::end_dialog)); + manager.CompleteChanged.connect (mem_fun (*close_button, &Gtk::Button::set_sensitive)); + + /* Load state before hooking up the rest of the signals */ + + load_state (format); + + /* Name entry */ + + name_entry.signal_changed().connect (mem_fun (*this, &ExportFormatDialog::update_name)); + + /* Normalize, silence and src_quality signals */ + + trim_start_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_trim_start_selection)); + trim_end_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_trim_end_selection)); + + normalize_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_normalize_selection)); + normalize_spinbutton.signal_value_changed().connect (mem_fun (*this, &ExportFormatDialog::update_normalize_selection)); + + silence_start_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_silence_start_selection)); + silence_start_clock.ValueChanged.connect (mem_fun (*this, &ExportFormatDialog::update_silence_start_selection)); + + silence_end_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_silence_end_selection)); + silence_end_clock.ValueChanged.connect (mem_fun (*this, &ExportFormatDialog::update_silence_end_selection)); + + src_quality_combo.signal_changed().connect (mem_fun (*this, &ExportFormatDialog::update_src_quality_selection)); + + /* Format table signals */ + + Gtk::CellRendererToggle *toggle = dynamic_cast(compatibility_view.get_column_cell_renderer (0)); + toggle->signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_compatibility_selection)); + compatibility_select_connection = compatibility_view.get_selection()->signal_changed().connect (mem_fun (*this, &ExportFormatDialog::prohibit_compatibility_selection)); + + quality_view.get_selection()->signal_changed().connect (mem_fun(*this, &ExportFormatDialog::update_quality_selection)); + format_view.get_selection()->signal_changed().connect (mem_fun(*this, &ExportFormatDialog::update_format_selection)); + sample_rate_view.get_selection()->signal_changed().connect (mem_fun(*this, &ExportFormatDialog::update_sample_rate_selection)); + + /* Encoding option signals */ + + sample_format_view.get_selection()->signal_changed().connect (mem_fun(*this, &ExportFormatDialog::update_sample_format_selection)); + dither_type_view.get_selection()->signal_changed().connect (mem_fun(*this, &ExportFormatDialog::update_dither_type_selection)); + + tag_checkbox.signal_toggled().connect (mem_fun (*this, &ExportFormatDialog::update_tagging_selection)); + + /* Finalize */ + + show_all_children(); +} + +ExportFormatDialog::~ExportFormatDialog () +{ + +} + +void +ExportFormatDialog::revert () +{ + ++applying_changes_from_engine; + + format->set_state (original_state); + load_state (format); + + --applying_changes_from_engine; +} + +void +ExportFormatDialog::set_session (ARDOUR::Session* s) +{ + session = s; + if (!session) { + return; + } + + silence_start_clock.set_session (s); + silence_end_clock.set_session (s); + + update_clock (silence_start_clock, silence_start); + update_clock (silence_end_clock, silence_end); + + /* Select native samplerate if no selection is yet made */ + + if (sample_rate_view.get_selection()->count_selected_rows() == 0) { + Gtk::ListStore::Children::iterator it; + for (it = sample_rate_list->children().begin(); it != sample_rate_list->children().end(); ++it) { + if ((nframes_t) (*it)->get_value (sample_rate_cols.ptr)->rate == session->nominal_frame_rate()) { + sample_rate_view.get_selection()->select (it); + break; + } + } + } +} + +void +ExportFormatDialog::load_state (FormatPtr spec) +{ + name_entry.set_text (spec->name()); + + normalize_checkbox.set_active (spec->normalize()); + normalize_spinbutton.set_value (spec->normalize_target()); + + trim_start_checkbox.set_active (spec->trim_beginning()); + silence_start = spec->silence_beginning_time(); + silence_start_checkbox.set_active (spec->silence_beginning() > 0); + + trim_end_checkbox.set_active (spec->trim_end()); + silence_end = spec->silence_end_time(); + silence_end_checkbox.set_active (spec->silence_end() > 0); + + for (Gtk::ListStore::Children::iterator it = src_quality_list->children().begin(); it != src_quality_list->children().end(); ++it) { + if (it->get_value (src_quality_cols.id) == spec->src_quality()) { + src_quality_combo.set_active (it); + break; + } + } + + for (Gtk::ListStore::Children::iterator it = format_list->children().begin(); it != format_list->children().end(); ++it) { + if (it->get_value (format_cols.ptr)->get_format_id() == spec->format_id()) { + it->get_value (format_cols.ptr)->set_selected (true); + break; + } + } + + for (Gtk::ListStore::Children::iterator it = sample_rate_list->children().begin(); it != sample_rate_list->children().end(); ++it) { + if (it->get_value (sample_rate_cols.ptr)->rate == spec->sample_rate()) { + it->get_value (sample_rate_cols.ptr)->set_selected (true); + break; + } + } + + if (spec->sample_format()) { + for (Gtk::ListStore::Children::iterator it = sample_format_list->children().begin(); it != sample_format_list->children().end(); ++it) { + if (it->get_value (sample_format_cols.ptr)->format == spec->sample_format()) { + it->get_value (sample_format_cols.ptr)->set_selected (true); + break; + } + } + + for (Gtk::ListStore::Children::iterator it = dither_type_list->children().begin(); it != dither_type_list->children().end(); ++it) { + if (it->get_value (dither_type_cols.ptr)->type == spec->dither_type()) { + it->get_value (dither_type_cols.ptr)->set_selected (true); + break; + } + } + } + + tag_checkbox.set_active (spec->tag()); +} + +void +ExportFormatDialog::init_format_table () +{ + + format_table.set_spacings (1); + + format_table.attach (compatibility_label, 0, 1, 0, 1); + format_table.attach (quality_label, 1, 2, 0, 1); + format_table.attach (format_label, 2, 3, 0, 1); + format_table.attach (sample_rate_label, 3, 4, 0, 1); + + format_table.attach (compatibility_view, 0, 1, 1, 2); + format_table.attach (quality_view, 1, 2, 1, 2); + format_table.attach (format_view, 2, 3, 1, 2); + format_table.attach (sample_rate_view, 3, 4, 1, 2); + + format_table.attach (src_quality_label, 0, 3, 2, 3); + format_table.attach (src_quality_combo, 3, 4, 2, 3); + + compatibility_view.set_headers_visible (false); + quality_view.set_headers_visible (false); + format_view.set_headers_visible (false); + sample_rate_view.set_headers_visible (false); + + /*** Table entries ***/ + + Gtk::TreeModel::iterator iter; + Gtk::TreeModel::Row row; + + /* Compatibilities */ + + compatibility_list = Gtk::ListStore::create (compatibility_cols); + compatibility_view.set_model (compatibility_list); + + ExportFormatManager::CompatList const & compat_list = manager.get_compatibilities(); + + for (ExportFormatManager::CompatList::const_iterator it = compat_list.begin(); it != compat_list.end(); ++it) { + iter = compatibility_list->append(); + row = *iter; + + row[compatibility_cols.ptr] = *it; + row[compatibility_cols.selected] = false; + row[compatibility_cols.label] = (*it)->name(); + + WeakCompatPtr ptr (*it); + (*it)->SelectChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_compatibility_selection), ptr)); + } + + compatibility_view.append_column_editable ("", compatibility_cols.selected); + + Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); + text_renderer->property_editable() = false; + + Gtk::TreeView::Column* column = compatibility_view.get_column (0); + column->pack_start (*text_renderer); + column->add_attribute (text_renderer->property_text(), compatibility_cols.label); + + /* Qualities */ + + quality_list = Gtk::ListStore::create (quality_cols); + quality_view.set_model (quality_list); + + ExportFormatManager::QualityList const & qualities = manager.get_qualities (); + + for (ExportFormatManager::QualityList::const_iterator it = qualities.begin(); it != qualities.end(); ++it) { + iter = quality_list->append(); + row = *iter; + + row[quality_cols.ptr] = *it; + row[quality_cols.color] = "white"; + row[quality_cols.label] = (*it)->name(); + + WeakQualityPtr ptr (*it); + (*it)->SelectChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_quality_selection), ptr)); + (*it)->CompatibleChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_quality_compatibility), ptr)); + } + + quality_view.append_column ("", quality_cols.label); + + /* Formats */ + + format_list = Gtk::ListStore::create (format_cols); + format_view.set_model (format_list); + + ExportFormatManager::FormatList const & formats = manager.get_formats (); + + for (ExportFormatManager::FormatList::const_iterator it = formats.begin(); it != formats.end(); ++it) { + iter = format_list->append(); + row = *iter; + + row[format_cols.ptr] = *it; + row[format_cols.color] = "white"; + row[format_cols.label] = (*it)->name(); + + WeakFormatPtr ptr (*it); + (*it)->SelectChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_format_selection), ptr)); + (*it)->CompatibleChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_format_compatibility), ptr)); + + /* Encoding options */ + + boost::shared_ptr hsf; + + if (hsf = boost::dynamic_pointer_cast (*it)) { + hsf->SampleFormatSelectChanged.connect (sigc::mem_fun (*this, &ExportFormatDialog::change_sample_format_selection)); + hsf->SampleFormatCompatibleChanged.connect (sigc::mem_fun (*this, &ExportFormatDialog::change_sample_format_compatibility)); + + hsf->DitherTypeSelectChanged.connect (sigc::mem_fun (*this, &ExportFormatDialog::change_dither_type_selection)); + hsf->DitherTypeCompatibleChanged.connect (sigc::mem_fun (*this, &ExportFormatDialog::change_dither_type_compatibility)); + } + } + + format_view.append_column ("", format_cols.label); + + /* Sample Rates */ + + sample_rate_list = Gtk::ListStore::create (sample_rate_cols); + sample_rate_view.set_model (sample_rate_list); + + ExportFormatManager::SampleRateList const & rates = manager.get_sample_rates (); + + for (ExportFormatManager::SampleRateList::const_iterator it = rates.begin(); it != rates.end(); ++it) { + iter = sample_rate_list->append(); + row = *iter; + + row[sample_rate_cols.ptr] = *it; + row[sample_rate_cols.color] = "white"; + row[sample_rate_cols.label] = (*it)->name(); + + WeakSampleRatePtr ptr (*it); + (*it)->SelectChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_sample_rate_selection), ptr)); + (*it)->CompatibleChanged.connect (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::change_sample_rate_compatibility), ptr)); + } + + sample_rate_view.append_column ("", sample_rate_cols.label); + + /* Color rendering */ + + Gtk::TreeViewColumn * label_col; + Gtk::CellRendererText * renderer; + + label_col = quality_view.get_column(0); + renderer = dynamic_cast (quality_view.get_column_cell_renderer (0)); + label_col->add_attribute(renderer->property_foreground(), quality_cols.color); + + label_col = format_view.get_column(0); + renderer = dynamic_cast (format_view.get_column_cell_renderer (0)); + label_col->add_attribute(renderer->property_foreground(), format_cols.color); + + label_col = sample_rate_view.get_column(0); + renderer = dynamic_cast (sample_rate_view.get_column_cell_renderer (0)); + label_col->add_attribute(renderer->property_foreground(), sample_rate_cols.color); + + /* SRC Qualities */ + + src_quality_list = Gtk::ListStore::create (src_quality_cols); + src_quality_combo.set_model (src_quality_list); + + iter = src_quality_list->append(); + row = *iter; + row[src_quality_cols.id] = ExportFormatBase::SRC_SincBest; + row[src_quality_cols.label] = _("Best (sinc)"); + + iter = src_quality_list->append(); + row = *iter; + row[src_quality_cols.id] = ExportFormatBase::SRC_SincMedium; + row[src_quality_cols.label] = _("Medium (sinc)"); + + iter = src_quality_list->append(); + row = *iter; + row[src_quality_cols.id] = ExportFormatBase::SRC_SincFast; + row[src_quality_cols.label] = _("Fast (sinc)"); + + iter = src_quality_list->append(); + row = *iter; + row[src_quality_cols.id] = ExportFormatBase::SRC_Linear; + row[src_quality_cols.label] = _("Linear"); + + iter = src_quality_list->append(); + row = *iter; + row[src_quality_cols.id] = ExportFormatBase::SRC_ZeroOrderHold; + row[src_quality_cols.label] = _("Zero order hold"); + + src_quality_combo.pack_start (src_quality_cols.label); + src_quality_combo.set_active (0); +} + +void +ExportFormatDialog::init_encoding_option_widgets () +{ + Gtk::TreeViewColumn * label_col; + Gtk::CellRendererText * renderer; + + sample_format_list = Gtk::ListStore::create (sample_format_cols); + sample_format_view.set_model (sample_format_list); + sample_format_view.set_headers_visible (false); + sample_format_view.append_column ("", sample_format_cols.label); + label_col = sample_format_view.get_column(0); + renderer = dynamic_cast (sample_format_view.get_column_cell_renderer (0)); + label_col->add_attribute(renderer->property_foreground(), sample_format_cols.color); + + dither_type_list = Gtk::ListStore::create (dither_type_cols); + dither_type_view.set_model (dither_type_list); + dither_type_view.set_headers_visible (false); + dither_type_view.append_column ("", dither_type_cols.label); + label_col = dither_type_view.get_column(0); + renderer = dynamic_cast (dither_type_view.get_column_cell_renderer (0)); + label_col->add_attribute(renderer->property_foreground(), dither_type_cols.color); + +} + +void +ExportFormatDialog::update_compatibility_selection (Glib::ustring const & path) +{ + + Gtk::TreeModel::iterator iter = compatibility_view.get_model ()->get_iter (path); + ExportFormatManager::CompatPtr ptr = iter->get_value (compatibility_cols.ptr); + bool state = iter->get_value (compatibility_cols.selected); + + iter->set_value (compatibility_cols.selected, state); + ptr->set_selected (state); + +} + +void +ExportFormatDialog::update_quality_selection () +{ + update_selection (quality_list, quality_view, quality_cols); +} + +void +ExportFormatDialog::update_format_selection () +{ + update_selection (format_list, format_view, format_cols); +} + +void +ExportFormatDialog::update_sample_rate_selection () +{ + update_selection (sample_rate_list, sample_rate_view, sample_rate_cols); +} + +void +ExportFormatDialog::update_sample_format_selection () +{ + update_selection (sample_format_list, sample_format_view, sample_format_cols); +} + +void +ExportFormatDialog::update_dither_type_selection () +{ + update_selection (dither_type_list, dither_type_view, dither_type_cols); +} + +template +void +ExportFormatDialog::update_selection (Glib::RefPtr & list, Gtk::TreeView & view, ColsT & cols) +{ + if (applying_changes_from_engine) { + return; + } + + Gtk::ListStore::Children::iterator it; + Glib::RefPtr selection = view.get_selection(); + + for (it = list->children().begin(); it != list->children().end(); ++it) { + bool selected = selection->is_selected (it); + it->get_value (cols.ptr)->set_selected (selected); + } +} + +void +ExportFormatDialog::change_compatibility_selection (bool select, WeakCompatPtr compat) +{ + ++applying_changes_from_engine; + + ExportFormatManager::CompatPtr ptr = compat.lock(); + + for (Gtk::ListStore::Children::iterator it = compatibility_list->children().begin(); it != compatibility_list->children().end(); ++it) { + if (it->get_value (compatibility_cols.ptr) == ptr) { + it->set_value (compatibility_cols.selected, select); + break; + } + } + + --applying_changes_from_engine; +} + +void +ExportFormatDialog::change_quality_selection (bool select, WeakQualityPtr quality) +{ + change_selection (select, quality, quality_list, quality_view, quality_cols); +} + +void +ExportFormatDialog::change_format_selection (bool select, WeakFormatPtr format) +{ + change_selection (select, format, format_list, format_view, format_cols); + + ExportFormatManager::FormatPtr ptr = format.lock(); + + if (select && ptr) { + change_encoding_options (ptr); + } +} + +void +ExportFormatDialog::change_sample_rate_selection (bool select, WeakSampleRatePtr rate) +{ + change_selection (select, rate, sample_rate_list, sample_rate_view, sample_rate_cols); + + if (select) { + ExportFormatManager::SampleRatePtr ptr = rate.lock(); + if (ptr && session) { + src_quality_combo.set_sensitive ((uint32_t) ptr->rate != session->frame_rate()); + } + } +} + +void +ExportFormatDialog::change_sample_format_selection (bool select, WeakSampleFormatPtr format) +{ + change_selection (select, format, sample_format_list, sample_format_view, sample_format_cols); +} + +void +ExportFormatDialog::change_dither_type_selection (bool select, WeakDitherTypePtr type) +{ + change_selection (select, type, dither_type_list, dither_type_view, dither_type_cols); +} + +template +void +ExportFormatDialog::change_selection (bool select, boost::weak_ptr w_ptr, Glib::RefPtr & list, Gtk::TreeView & view, ColsT & cols) +{ + ++applying_changes_from_engine; + + boost::shared_ptr ptr = w_ptr.lock(); + + Gtk::ListStore::Children::iterator it; + Glib::RefPtr selection; + + selection = view.get_selection(); + + if (!ptr) { + selection->unselect_all(); + } else { + for (it = list->children().begin(); it != list->children().end(); ++it) { + if (it->get_value (cols.ptr) == ptr) { + if (select) { + selection->select (it); + } else { + selection->unselect (it); + } + break; + } + } + } + + --applying_changes_from_engine; +} + +void +ExportFormatDialog::change_quality_compatibility (bool compatibility, WeakQualityPtr quality) +{ + change_compatibility (compatibility, quality, quality_list, quality_cols); +} + +void +ExportFormatDialog::change_format_compatibility (bool compatibility, WeakFormatPtr format) +{ + change_compatibility (compatibility, format, format_list, format_cols); +} + +void +ExportFormatDialog::change_sample_rate_compatibility (bool compatibility, WeakSampleRatePtr rate) +{ + change_compatibility (compatibility, rate, sample_rate_list, sample_rate_cols); +} + +void +ExportFormatDialog::change_sample_format_compatibility (bool compatibility, WeakSampleFormatPtr format) +{ + change_compatibility (compatibility, format, sample_format_list, sample_format_cols); +} + +void +ExportFormatDialog::change_dither_type_compatibility (bool compatibility, WeakDitherTypePtr type) +{ + change_compatibility (compatibility, type, dither_type_list, dither_type_cols, "red"); +} + +template +void +ExportFormatDialog::change_compatibility (bool compatibility, boost::weak_ptr w_ptr, Glib::RefPtr & list, ColsT & cols, + Glib::ustring const & c_incompatible, Glib::ustring const & c_compatible) +{ + boost::shared_ptr ptr = w_ptr.lock(); + + Gtk::ListStore::Children::iterator it; + for (it = list->children().begin(); it != list->children().end(); ++it) { + if (it->get_value (cols.ptr) == ptr) { + it->set_value (cols.color, compatibility ? c_compatible : c_incompatible); + break; + } + } +} + +void +ExportFormatDialog::update_name () +{ + manager.set_name (name_entry.get_text()); +} + +void +ExportFormatDialog::update_trim_start_selection () +{ + manager.select_trim_beginning (trim_start_checkbox.get_active()); +} + +void +ExportFormatDialog::update_trim_end_selection () +{ + manager.select_trim_end (trim_end_checkbox.get_active()); +} + +void +ExportFormatDialog::update_normalize_selection () +{ + manager.select_normalize (normalize_checkbox.get_active()); + manager.select_normalize_target (normalize_spinbutton.get_value ()); +} + +void +ExportFormatDialog::update_silence_start_selection () +{ + update_time (silence_start, silence_start_clock); + AnyTime zero; + zero.type = AnyTime::SMPTE; + manager.select_silence_beginning (silence_start_checkbox.get_active() ? silence_start : zero); +} + +void +ExportFormatDialog::update_silence_end_selection () +{ + update_time (silence_end, silence_end_clock); + AnyTime zero; + zero.type = AnyTime::SMPTE; + manager.select_silence_end (silence_end_checkbox.get_active() ? silence_end : zero); +} + +void +ExportFormatDialog::update_clock (AudioClock & clock, ARDOUR::AnyTime const & time) +{ + // TODO position + clock.set (session->convert_to_frames_at (0, time), true); + + AudioClock::Mode mode; + + switch (time.type) { + case AnyTime::SMPTE: + mode = AudioClock::SMPTE; + break; + case AnyTime::BBT: + mode = AudioClock::BBT; + break; + case AnyTime::Frames: + mode = AudioClock::Frames; + break; + case AnyTime::Seconds: + mode = AudioClock::MinSec; + break; + } + + clock.set_mode (mode); +} + +void +ExportFormatDialog::update_time (AnyTime & time, AudioClock const & clock) +{ + if (!session) { + return; + } + + nframes_t frames = clock.current_duration(); + + switch (clock.mode()) { + case AudioClock::SMPTE: + time.type = AnyTime::SMPTE; + session->smpte_time (frames, time.smpte); + break; + case AudioClock::BBT: + time.type = AnyTime::BBT; + session->bbt_time (frames, time.bbt); + break; + case AudioClock::MinSec: + time.type = AnyTime::Seconds; + time.seconds = (double) frames / session->frame_rate(); + break; + case AudioClock::Frames: + time.type = AnyTime::Frames; + time.frames = frames; + break; + case AudioClock::Off: + silence_end_checkbox.set_active (false); + return; + } +} + +void +ExportFormatDialog::update_src_quality_selection () +{ + Gtk::TreeModel::const_iterator iter = src_quality_combo.get_active(); + ExportFormatBase::SRCQuality quality = iter->get_value (src_quality_cols.id); + manager.select_src_quality (quality); +} + +void +ExportFormatDialog::update_tagging_selection () +{ + manager.select_tagging (tag_checkbox.get_active()); +} + +void +ExportFormatDialog::change_encoding_options (ExportFormatManager::FormatPtr ptr) +{ + empty_encoding_option_table (); + + boost::shared_ptr linear_ptr; + boost::shared_ptr ogg_ptr; + boost::shared_ptr flac_ptr; + boost::shared_ptr bwf_ptr; + + if (linear_ptr = boost::dynamic_pointer_cast (ptr)) { + show_linear_enconding_options (linear_ptr); + } else if (ogg_ptr = boost::dynamic_pointer_cast (ptr)) { + show_ogg_enconding_options (ogg_ptr); + } else if (flac_ptr = boost::dynamic_pointer_cast (ptr)) { + show_flac_enconding_options (flac_ptr); + } else if (bwf_ptr = boost::dynamic_pointer_cast (ptr)) { + show_bwf_enconding_options (bwf_ptr); + } else { + std::cout << "Unrecognized format!" << std::endl; + } +} + +void +ExportFormatDialog::empty_encoding_option_table () +{ + encoding_options_table.foreach (sigc::bind (sigc::mem_fun (*this, &ExportFormatDialog::remove_widget), &encoding_options_table)); +} + +void +ExportFormatDialog::remove_widget (Gtk::Widget & to_remove, Gtk::Container * remove_from) +{ + remove_from->remove (to_remove); +} + +void +ExportFormatDialog::show_linear_enconding_options (boost::shared_ptr ptr) +{ + /* Set label and pack table */ + + encoding_options_label.set_label (_("Linear encoding options")); + + encoding_options_table.resize (2, 2); + encoding_options_table.attach (sample_format_label, 0, 1, 0, 1); + encoding_options_table.attach (dither_label, 1, 2, 0, 1); + encoding_options_table.attach (sample_format_view, 0, 1, 1, 2); + encoding_options_table.attach (dither_type_view, 1, 2, 1, 2); + + fill_sample_format_lists (boost::dynamic_pointer_cast (ptr)); + + show_all_children (); +} + +void +ExportFormatDialog::show_ogg_enconding_options (boost::shared_ptr ptr) +{ + encoding_options_label.set_label (_("Ogg Vorbis options")); + + encoding_options_table.resize (1, 1); + encoding_options_table.attach (tag_checkbox, 0, 1, 0, 1); + + update_tagging_selection (); + + show_all_children (); +} + +void +ExportFormatDialog::show_flac_enconding_options (boost::shared_ptr ptr) +{ + encoding_options_label.set_label (_("FLAC options")); + + encoding_options_table.resize (3, 2); + encoding_options_table.attach (sample_format_label, 0, 1, 0, 1); + encoding_options_table.attach (dither_label, 1, 2, 0, 1); + encoding_options_table.attach (sample_format_view, 0, 1, 1, 2); + encoding_options_table.attach (dither_type_view, 1, 2, 1, 2); + encoding_options_table.attach (tag_checkbox, 0, 2, 2, 3); + + fill_sample_format_lists (boost::dynamic_pointer_cast (ptr)); + + show_all_children (); +} + +void +ExportFormatDialog::show_bwf_enconding_options (boost::shared_ptr ptr) +{ + encoding_options_label.set_label (_("Broadcast Wave options")); + + encoding_options_table.resize (2, 2); + encoding_options_table.attach (sample_format_label, 0, 1, 0, 1); + encoding_options_table.attach (dither_label, 1, 2, 0, 1); + encoding_options_table.attach (sample_format_view, 0, 1, 1, 2); + encoding_options_table.attach (dither_type_view, 1, 2, 1, 2); + + fill_sample_format_lists (boost::dynamic_pointer_cast (ptr)); + + show_all_children (); +} + +void +ExportFormatDialog::fill_sample_format_lists (boost::shared_ptr ptr) +{ + /* Fill lists */ + + Gtk::TreeModel::iterator iter; + Gtk::TreeModel::Row row; + + sample_format_list->clear (); + + HasSampleFormat::SampleFormatList const & formats = ptr->get_sample_formats (); + + for (HasSampleFormat::SampleFormatList::const_iterator it = formats.begin(); it != formats.end(); ++it) { + iter = sample_format_list->append(); + row = *iter; + + row[sample_format_cols.ptr] = *it; + row[sample_format_cols.color] = (*it)->compatible() ? "white" : "red"; + row[sample_format_cols.label] = (*it)->name(); + + if ((*it)->selected()) { + sample_format_view.get_selection()->select (iter); + } + } + + dither_type_list->clear (); + + HasSampleFormat::DitherTypeList const & types = ptr->get_dither_types (); + + for (HasSampleFormat::DitherTypeList::const_iterator it = types.begin(); it != types.end(); ++it) { + iter = dither_type_list->append(); + row = *iter; + + row[dither_type_cols.ptr] = *it; + row[dither_type_cols.color] = "white"; + row[dither_type_cols.label] = (*it)->name(); + + if ((*it)->selected()) { + dither_type_view.get_selection()->select (iter); + } + } +} + +void +ExportFormatDialog::end_dialog () +{ + hide_all (); +} + +void +ExportFormatDialog::prohibit_compatibility_selection () +{ + compatibility_select_connection.block (true); + compatibility_view.get_selection()->unselect_all (); + compatibility_select_connection.block (false); +} diff --git a/gtk2_ardour/export_format_dialog.h b/gtk2_ardour/export_format_dialog.h new file mode 100644 index 0000000000..fed081f9f0 --- /dev/null +++ b/gtk2_ardour/export_format_dialog.h @@ -0,0 +1,308 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_format_dialog_h__ +#define __export_format_dialog_h__ + +#include +#include +#include +#include + +#include + +#include "ardour_dialog.h" +#include "audio_clock.h" + +#include + +class ExportFormatDialog : public ArdourDialog { + private: + + typedef ARDOUR::ExportFormatManager::WeakCompatPtr WeakCompatPtr; + typedef ARDOUR::ExportFormatManager::WeakQualityPtr WeakQualityPtr; + typedef ARDOUR::ExportFormatManager::WeakFormatPtr WeakFormatPtr; + typedef ARDOUR::ExportFormatManager::WeakSampleRatePtr WeakSampleRatePtr; + typedef ARDOUR::ExportFormatManager::WeakSampleFormatPtr WeakSampleFormatPtr; + typedef ARDOUR::ExportFormatManager::WeakDitherTypePtr WeakDitherTypePtr; + + typedef boost::shared_ptr FormatPtr; + + + public: + + explicit ExportFormatDialog (FormatPtr format, bool new_dialog = false); + ~ExportFormatDialog (); + + void set_session (ARDOUR::Session* s); + + private: + + FormatPtr format; + ARDOUR::ExportFormatManager manager; + + XMLNode & original_state; + + ARDOUR::AnyTime silence_start; + ARDOUR::AnyTime silence_end; + + void end_dialog (); + void revert (); + + /*** Init functions ***/ + + void load_state (FormatPtr spec); + void init_format_table (); + void init_encoding_option_widgets (); + + /*** Interactive selections ***/ + + /* These are connected to signals from GUI components, and should change element states */ + + void update_compatibility_selection (Glib::ustring const & path); + void update_quality_selection (); + void update_format_selection (); + void update_sample_rate_selection (); + void update_sample_format_selection (); + void update_dither_type_selection (); + + template + void update_selection (Glib::RefPtr & list, Gtk::TreeView & view, ColsT & cols); + + /* These are connected to signals from elements, and should only update the gui */ + + void change_compatibility_selection (bool select, WeakCompatPtr compat); + + void change_quality_selection (bool select, WeakQualityPtr quality); + void change_format_selection (bool select, WeakFormatPtr format); + void change_sample_rate_selection (bool select, WeakSampleRatePtr rate); + void change_sample_format_selection (bool select, WeakSampleFormatPtr format); + void change_dither_type_selection (bool select, WeakDitherTypePtr type); + + template + void change_selection (bool select, boost::weak_ptr w_ptr, Glib::RefPtr & list, Gtk::TreeView & view, ColsT & cols); + + void change_quality_compatibility (bool compatibility, WeakQualityPtr quality); + void change_format_compatibility (bool compatibility, WeakFormatPtr format); + void change_sample_rate_compatibility (bool compatibility, WeakSampleRatePtr rate); + void change_sample_format_compatibility (bool compatibility, WeakSampleFormatPtr format); + void change_dither_type_compatibility (bool compatibility, WeakDitherTypePtr type); + + template + void change_compatibility (bool compatibility, boost::weak_ptr w_ptr, Glib::RefPtr & list, ColsT & cols, + Glib::ustring const & c_incompatible = "red", Glib::ustring const & c_compatible = "white"); + + uint32_t applying_changes_from_engine; + + /*** Non-interactive selections ***/ + + void update_name (); + + void update_trim_start_selection (); + void update_trim_end_selection (); + + void update_normalize_selection (); + void update_silence_start_selection (); + void update_silence_end_selection (); + + void update_clock (AudioClock & clock, ARDOUR::AnyTime const & time); + void update_time (ARDOUR::AnyTime & time, AudioClock const & clock); + + void update_src_quality_selection (); + void update_tagging_selection (); + + /*** Encoding options */ + + void change_encoding_options (ARDOUR::ExportFormatManager::FormatPtr ptr); + + void empty_encoding_option_table (); + void remove_widget (Gtk::Widget & to_remove, Gtk::Container * remove_from); + + void show_linear_enconding_options (boost::shared_ptr ptr); + void show_ogg_enconding_options (boost::shared_ptr ptr); + void show_flac_enconding_options (boost::shared_ptr ptr); + void show_bwf_enconding_options (boost::shared_ptr ptr); + + void fill_sample_format_lists (boost::shared_ptr ptr); + + /*** GUI components ***/ + + /* Name, new and remove */ + + Gtk::HBox name_hbox; + + Gtk::Label name_label; + Gtk::Entry name_entry; + + /* Normalize */ + + Gtk::HBox normalize_hbox; + Gtk::CheckButton normalize_checkbox; + Gtk::SpinButton normalize_spinbutton; + Gtk::Adjustment normalize_adjustment; + Gtk::Label normalize_db_label; + + /* Silence */ + + Gtk::Table silence_table; + + Gtk::CheckButton trim_start_checkbox; + Gtk::CheckButton silence_start_checkbox; + AudioClock silence_start_clock; + + Gtk::CheckButton trim_end_checkbox; + Gtk::CheckButton silence_end_checkbox; + AudioClock silence_end_clock; + + /* Format table */ + + struct CompatibilityCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn selected; + Gtk::TreeModelColumn label; + + CompatibilityCols () { add(ptr); add(selected); add(label); } + }; + CompatibilityCols compatibility_cols; + Glib::RefPtr compatibility_list; + + /* Hack to disallow row selection in compatibilities */ + void prohibit_compatibility_selection (); + sigc::connection compatibility_select_connection; + + struct QualityCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn color; + Gtk::TreeModelColumn label; + + QualityCols () { add(ptr); add(color); add(label); } + }; + QualityCols quality_cols; + Glib::RefPtr quality_list; + + struct FormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn color; + Gtk::TreeModelColumn label; + + FormatCols () { add(ptr); add(color); add(label); } + }; + FormatCols format_cols; + Glib::RefPtr format_list; + + struct SampleRateCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn color; + Gtk::TreeModelColumn label; + + SampleRateCols () { add(ptr); add(color); add(label); } + }; + SampleRateCols sample_rate_cols; + Glib::RefPtr sample_rate_list; + + Gtk::Table format_table; + + Gtk::Label compatibility_label; + Gtk::Label quality_label; + Gtk::Label format_label; + Gtk::Label sample_rate_label; + + Gtk::TreeView compatibility_view; + Gtk::TreeView quality_view; + Gtk::TreeView format_view; + Gtk::TreeView sample_rate_view; + + /* SRC quality combo */ + + struct SRCQualityCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn id; + Gtk::TreeModelColumn label; + + SRCQualityCols () { add(id); add(label); } + }; + SRCQualityCols src_quality_cols; + Glib::RefPtr src_quality_list; + + Gtk::Label src_quality_label; + Gtk::ComboBox src_quality_combo; + + /* Common encoding option components */ + + Gtk::VBox encoding_options_vbox; + Gtk::Label encoding_options_label; + + Gtk::Table encoding_options_table; + + /* Other common components */ + + Gtk::Button * revert_button; + Gtk::Button * close_button; + + /*** Changing encoding option stuff ***/ + + /* Linear */ + + struct SampleFormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn color; + Gtk::TreeModelColumn label; + + SampleFormatCols () { add(ptr); add(color); add(label); } + }; + SampleFormatCols sample_format_cols; + Glib::RefPtr sample_format_list; + + struct DitherTypeCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn ptr; + Gtk::TreeModelColumn color; + Gtk::TreeModelColumn label; + + DitherTypeCols () { add(ptr); add (color); add(label); } + }; + DitherTypeCols dither_type_cols; + Glib::RefPtr dither_type_list; + + Gtk::Label sample_format_label; + Gtk::Label dither_label; + + Gtk::TreeView sample_format_view; + Gtk::TreeView dither_type_view; + + /* Tagging */ + + Gtk::CheckButton tag_checkbox; + +}; + +#endif /* __export_format_dialog_h__ */ diff --git a/gtk2_ardour/export_format_selector.cc b/gtk2_ardour/export_format_selector.cc new file mode 100644 index 0000000000..1f1158a21f --- /dev/null +++ b/gtk2_ardour/export_format_selector.cc @@ -0,0 +1,169 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_format_selector.h" + +#include "export_format_dialog.h" + +#include +#include +#include + +#include "i18n.h" + +ExportFormatSelector::ExportFormatSelector () : + edit_button (Gtk::Stock::EDIT), + remove_button (Gtk::Stock::REMOVE), + new_button (Gtk::Stock::NEW) +{ + pack_start (format_combo, true, true, 0); + pack_start (edit_button, false, false, 3); + pack_start (remove_button, false, false, 3); + pack_start (new_button, false, false, 3); + + edit_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &ExportFormatSelector::open_edit_dialog), false))); + remove_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportFormatSelector::remove_format)); + new_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportFormatSelector::add_new_format)); + + /* Format combo */ + + format_list = Gtk::ListStore::create (format_cols); + format_combo.set_model (format_list); + format_combo.pack_start (format_cols.label); + format_combo.set_active (0); + + format_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportFormatSelector::update_format_combo)); +} + +ExportFormatSelector::~ExportFormatSelector () +{ + +} + +void +ExportFormatSelector::set_state (ARDOUR::ExportProfileManager::FormatStatePtr const state_, ARDOUR::Session * session_) +{ + session = session_; + state = state_; + + update_format_list (); +} + +void +ExportFormatSelector::update_format_list () +{ + FormatPtr format_to_select = state->format; + format_list->clear(); + + if (state->list->empty()) { + edit_button.set_sensitive (false); + remove_button.set_sensitive (false); + return; + } else { + edit_button.set_sensitive (true); + remove_button.set_sensitive (true); + } + + Gtk::ListStore::iterator tree_it; + + for (FormatList::const_iterator it = state->list->begin(); it != state->list->end(); ++it) { + tree_it = format_list->append(); + tree_it->set_value (format_cols.format, *it); + tree_it->set_value (format_cols.label, (*it)->description()); + } + + if (format_combo.get_active_row_number() == -1) { + format_combo.set_active (0); + } + + select_format (format_to_select); +} + +void +ExportFormatSelector::select_format (FormatPtr f) +{ + Gtk::TreeModel::Children::iterator it; + for (it = format_list->children().begin(); it != format_list->children().end(); ++it) { + if (it->get_value (format_cols.format) == f) { + format_combo.set_active (it); + break; + } + } + + CriticalSelectionChanged(); +} + +void +ExportFormatSelector::add_new_format () +{ + FormatPtr new_format = state->format = NewFormat (state->format); + + if (open_edit_dialog (true) != Gtk::RESPONSE_APPLY) { + remove_format(); + if (state->list->empty()) { + state->format.reset (); + } + } +} + +void +ExportFormatSelector::remove_format () +{ + FormatPtr remove; + Gtk::TreeModel::iterator it = format_combo.get_active(); + remove = it->get_value (format_cols.format); + FormatRemoved (remove); +} + +int +ExportFormatSelector::open_edit_dialog (bool new_dialog) +{ + ExportFormatDialog dialog (state->format, new_dialog); + dialog.set_session (session); + Gtk::ResponseType response = (Gtk::ResponseType) dialog.run(); + if (response == Gtk::RESPONSE_APPLY) { + update_format_description (); + FormatEdited (state->format); + CriticalSelectionChanged(); + } + return response; +} + +void +ExportFormatSelector::update_format_combo () +{ + Gtk::TreeModel::iterator it = format_combo.get_active(); + if (format_list->iter_is_valid (it)) { + state->format = it->get_value(format_cols.format); + } else if (!format_list->children().empty()) { + format_combo.set_active (0); + } else { + edit_button.set_sensitive (false); + remove_button.set_sensitive (false); + } + + CriticalSelectionChanged(); +} + +void +ExportFormatSelector::update_format_description () +{ + format_combo.get_active()->set_value(format_cols.label, state->format->description()); +} diff --git a/gtk2_ardour/export_format_selector.h b/gtk2_ardour/export_format_selector.h new file mode 100644 index 0000000000..d4e4ae0110 --- /dev/null +++ b/gtk2_ardour/export_format_selector.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_format_selector_h__ +#define __export_format_selector_h__ + +#include + +#include +#include +#include + +namespace ARDOUR { + class Session; + class ExportFormatSpecification; + class ExportProfileManager; +} + +/// +class ExportFormatSelector : public Gtk::HBox { + + private: + + typedef boost::shared_ptr FormatPtr; + typedef std::list FormatList; + + public: + + ExportFormatSelector (); + ~ExportFormatSelector (); + + void set_state (ARDOUR::ExportProfileManager::FormatStatePtr state_, ARDOUR::Session * session_); + void update_format_list (); + + sigc::signal FormatEdited; + sigc::signal FormatRemoved; + sigc::signal NewFormat; + + /* Compatibility with other elements */ + + sigc::signal CriticalSelectionChanged; + + private: + + void select_format (FormatPtr f); + void add_new_format (); + void remove_format (); + int open_edit_dialog (bool new_dialog = false); + void update_format_combo (); + void update_format_description (); + + ARDOUR::ExportProfileManager::FormatStatePtr state; + ARDOUR::Session * session; + + /*** GUI componenets ***/ + + struct FormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn format; + Gtk::TreeModelColumn label; + + FormatCols () { add (format); add (label); } + }; + FormatCols format_cols; + Glib::RefPtr format_list; + Gtk::ComboBox format_combo; + + Gtk::Button edit_button; + Gtk::Button remove_button; + Gtk::Button new_button; +}; + +#endif /* __export_format_selector_h__ */ diff --git a/gtk2_ardour/export_main_dialog.cc b/gtk2_ardour/export_main_dialog.cc new file mode 100644 index 0000000000..7a0dd8186f --- /dev/null +++ b/gtk2_ardour/export_main_dialog.cc @@ -0,0 +1,640 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_main_dialog.h" + +#include + +#include + +#include "utils.h" + +#include +#include +#include +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; + +ExportMainDialog::ExportMainDialog (PublicEditor & editor) : + ArdourDialog (_("Export")), + editor (editor), + + preset_label (_("Preset:"), Gtk::ALIGN_LEFT), + preset_save_button (Gtk::Stock::SAVE), + preset_remove_button (Gtk::Stock::REMOVE), + preset_new_button (Gtk::Stock::NEW), + + page_counter (1), + + warn_label ("", Gtk::ALIGN_LEFT), + list_files_label (_("Some already existing files will be overwritten."), Gtk::ALIGN_RIGHT), + list_files_button (_("List files")), + + timespan_label (_("Time Span"), Gtk::ALIGN_LEFT), + + channels_label (_("Channels"), Gtk::ALIGN_LEFT) +{ + /* Main packing */ + + get_vbox()->pack_start (preset_align, false, false, 0); + get_vbox()->pack_start (timespan_label, false, false, 0); + get_vbox()->pack_start (timespan_align, false, false, 0); + get_vbox()->pack_start (channels_label, false, false, 0); + get_vbox()->pack_start (channels_align, false, false, 0); + get_vbox()->pack_start (file_notebook, false, false, 0); + get_vbox()->pack_start (warn_container, true, true, 0); + get_vbox()->pack_start (progress_container, true, true, 0); + + timespan_align.add (timespan_selector); + timespan_align.set_padding (0, 12, 18, 0); + + channels_align.add (channel_selector); + channels_align.set_padding (0, 12, 18, 0); + + /* Preset manipulation */ + + preset_list = Gtk::ListStore::create (preset_cols); + preset_entry.set_model (preset_list); + preset_entry.set_text_column (preset_cols.label); + + preset_align.add (preset_hbox); + preset_align.set_padding (0, 12, 0, 0); + + preset_hbox.pack_start (preset_label, false, false, 0); + preset_hbox.pack_start (preset_entry, true, true, 6); + preset_hbox.pack_start (preset_save_button, false, false, 0); + preset_hbox.pack_start (preset_remove_button, false, false, 6); + preset_hbox.pack_start (preset_new_button, false, false, 0); + + preset_save_button.set_sensitive (false); + preset_remove_button.set_sensitive (false); + preset_new_button.set_sensitive (false); + + preset_select_connection = preset_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportMainDialog::select_preset)); + preset_save_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::save_current_preset)); + preset_new_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::save_current_preset)); + preset_remove_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::remove_current_preset)); + + /* warnings */ + + warn_container.pack_start (warn_hbox, true, true, 6); + warn_container.pack_end (list_files_hbox, false, false, 0); + + warn_hbox.pack_start (warn_label, true, true, 16); + warn_label.set_use_markup (true); + + list_files_hbox.pack_end (list_files_button, false, false, 6); + list_files_hbox.pack_end (list_files_label, false, false, 6); + list_files_label.set_use_markup (true); + + list_files_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::show_conflicting_files)); + + /* Progress indicators */ + + progress_container.pack_start (progress_label, false, false, 6); + progress_container.pack_start (progress_bar, false, false, 6); + + /* Buttons */ + + cancel_button = add_button (Gtk::Stock::CANCEL, RESPONSE_CANCEL); + rt_export_button = add_button (_("Realtime export"), RESPONSE_RT); + fast_export_button = add_button (_("Fast Export"), RESPONSE_FAST); + + cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::close_dialog)); + rt_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::export_rt)); + fast_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::export_fw)); + + /* Bolding for labels */ + + Pango::AttrList bold; + Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD); + bold.insert (b); + + timespan_label.set_attributes (bold); + channels_label.set_attributes (bold); + + /* Done! */ + + show_all_children (); + progress_container.hide_all(); +} + +ExportMainDialog::~ExportMainDialog () +{ + if (session) { + session->release_export_handler(); + } +} + +void +ExportMainDialog::set_session (ARDOUR::Session* s) +{ + session = s; + + /* Init handler and profile manager */ + + handler = session->get_export_handler (); + profile_manager.reset (new ExportProfileManager (*session)); + + /* Selection range */ + + TimeSelection const & time (editor.get_selection().time); + if (!time.empty()) { + profile_manager->set_selection_range (time.front().start, time.front().end); + } else { + profile_manager->set_selection_range (); + } + + /* Last notebook page */ + + new_file_button.add (*Gtk::manage (new Gtk::Image (::get_icon("add")))); + new_file_button.set_alignment (0, 0.5); + new_file_button.set_relief (Gtk::RELIEF_NONE); + + new_file_hbox.pack_start (new_file_button, true, true); + file_notebook.append_page (new_file_dummy, new_file_hbox); + file_notebook.set_tab_label_packing (new_file_dummy, true, true, Gtk::PACK_START); + new_file_hbox.show_all_children (); + + file_notebook.signal_switch_page().connect (sigc::mem_fun (*this, &ExportMainDialog::handle_page_change)); + new_file_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::add_new_file_page)); + + /* Load states */ + + profile_manager->load_profile (); + sync_with_manager (); + + /* Warnings */ + + timespan_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings)); + channel_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings)); + + update_warnings (); +} + +void +ExportMainDialog::select_timespan (Glib::ustring id) +{ + set_title ("Export Range"); + timespan_selector.select_one_range (id); +} + +void +ExportMainDialog::close_dialog () +{ + ExportStatus & status = session->export_status; + + if (status.running) { + status.abort(); + } + + hide_all (); + set_modal (false); + +} + +void +ExportMainDialog::sync_with_manager () +{ + /* Clear */ + + while (file_notebook.get_n_pages() > 1) { + file_notebook.remove_page (0); + } + + page_counter = 1; + last_visible_page = 0; + + /* Preset list */ + + preset_list->clear(); + + PresetList const & presets = profile_manager->get_presets(); + Gtk::ListStore::iterator tree_it; + + for (PresetList::const_iterator it = presets.begin(); it != presets.end(); ++it) { + tree_it = preset_list->append(); + tree_it->set_value (preset_cols.preset, *it); + tree_it->set_value (preset_cols.label, Glib::ustring ((*it)->name())); + + if (*it == current_preset) { + preset_select_connection.block (true); + preset_entry.set_active (tree_it); + preset_select_connection.block (false); + } + } + + /* Timespan and channel config */ + + timespan_selector.set_state (profile_manager->get_timespans().front(), session); + channel_selector.set_state (profile_manager->get_channel_configs().front(), session); + + /* File notebook */ + + ExportProfileManager::FormatStateList const & formats = profile_manager->get_formats (); + ExportProfileManager::FormatStateList::const_iterator format_it; + ExportProfileManager::FilenameStateList const & filenames = profile_manager->get_filenames (); + ExportProfileManager::FilenameStateList::const_iterator filename_it; + for (format_it = formats.begin(), filename_it = filenames.begin(); + format_it != formats.end() && filename_it != filenames.end(); + ++format_it, ++filename_it) { + add_file_page (*format_it, *filename_it); + } + + file_notebook.set_current_page (0); + update_warnings (); +} + +void +ExportMainDialog::update_warnings () +{ + /* Reset state */ + + warn_string = ""; + warn_label.set_markup (warn_string); + + list_files_hbox.hide (); + list_files_string = ""; + + fast_export_button->set_sensitive (true); + rt_export_button->set_sensitive (true); + + /* Add new warnings */ + + boost::shared_ptr warnings = profile_manager->get_warnings(); + + for (std::list::iterator it = warnings->errors.begin(); it != warnings->errors.end(); ++it) { + add_error (*it); + } + + for (std::list::iterator it = warnings->warnings.begin(); it != warnings->warnings.end(); ++it) { + add_warning (*it); + } + + if (!warnings->conflicting_filenames.empty()) { + list_files_hbox.show (); + for (std::list::iterator it = warnings->conflicting_filenames.begin(); it != warnings->conflicting_filenames.end(); ++it) { + ustring::size_type pos = it->find_last_of ("/"); + list_files_string += "\n" + it->substr (0, pos + 1) + "" + it->substr (pos + 1) + ""; + } + } +} + +void +ExportMainDialog::show_conflicting_files () +{ + ArdourDialog dialog (_("Files that will be overwritten"), true); + + Gtk::Label label ("", Gtk::ALIGN_LEFT); + label.set_use_markup (true); + label.set_markup (list_files_string); + + dialog.get_vbox()->pack_start (label); + dialog.add_button (Gtk::Stock::OK, 0); + dialog.show_all_children (); + + dialog.run(); +} + +void +ExportMainDialog::export_rt () +{ + profile_manager->prepare_for_export (); + handler->do_export (true); + show_progress (); +} + +void +ExportMainDialog::export_fw () +{ + profile_manager->prepare_for_export (); + handler->do_export (false); + show_progress (); +} + +void +ExportMainDialog::show_progress () +{ + ARDOUR::ExportStatus & status = session->export_status; + status.running = true; + + cancel_button->set_label (_("Stop Export")); + rt_export_button->set_sensitive (false); + fast_export_button->set_sensitive (false); + + progress_bar.set_fraction (0.0); + warn_container.hide_all(); + progress_container.show (); + progress_container.show_all_children (); + progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportMainDialog::progress_timeout), 100); + + gtk_main_iteration (); + while (status.running) { + if (gtk_events_pending()) { + gtk_main_iteration (); + } else { + usleep (10000); + } + } +} + +Glib::ustring +ExportMainDialog::get_nth_format_name (uint32_t n) +{ + FilePage * page; + if ((page = dynamic_cast (file_notebook.get_nth_page (n - 1)))) { + return page->get_format_name(); + } + return ""; +} + +gint +ExportMainDialog::progress_timeout () +{ + ARDOUR::ExportStatus & status = session->export_status; + + switch (status.stage) { + case export_None: + progress_label.set_text (""); + break; + case export_ReadTimespan: + progress_label.set_text (string_compose (_("Reading timespan %1 of %2"), status.timespan, status.total_timespans)); + break; + case export_PostProcess: + progress_label.set_text (string_compose (_("Processing file %2 of %3 (%1) from timespan %4 of %5"), + get_nth_format_name (status.format), + status.format, status.total_formats, + status.timespan, status.total_timespans)); + break; + case export_Write: + progress_label.set_text (string_compose (_("Encoding file %2 of %3 (%1) from timespan %4 of %5"), + get_nth_format_name (status.format), + status.format, status.total_formats, + status.timespan, status.total_timespans)); + break; + } + + progress_bar.set_fraction (status.progress); + return TRUE; +} + +void +ExportMainDialog::select_preset () +{ + Gtk::ListStore::iterator it = preset_entry.get_active (); + Glib::ustring text = preset_entry.get_entry()->get_text(); + + if (preset_list->iter_is_valid (it)) { + + previous_preset = current_preset = it->get_value (preset_cols.preset); + profile_manager->load_preset (current_preset); + sync_with_manager (); + + /* Make an edit, so that signal changed will be emitted on re-selection */ + + preset_select_connection.block (true); + preset_entry.get_entry()->set_text (""); + preset_entry.get_entry()->set_text (text); + preset_select_connection.block (false); + + } else { // Text has been edited + if (previous_preset && !text.compare (previous_preset->name())) { + + current_preset = previous_preset; + + } else { + current_preset.reset (); + profile_manager->load_preset (current_preset); + } + } + + preset_save_button.set_sensitive (current_preset); + preset_remove_button.set_sensitive (current_preset); + preset_new_button.set_sensitive (!current_preset && !text.empty()); +} + +void +ExportMainDialog::save_current_preset () +{ + if (!profile_manager) { return; } + + previous_preset = current_preset = profile_manager->save_preset (preset_entry.get_entry()->get_text()); + sync_with_manager (); + select_preset (); // Update preset widget states +} + +void +ExportMainDialog::remove_current_preset () +{ + if (!profile_manager) { return; } + + profile_manager->remove_preset(); + preset_entry.get_entry()->set_text (""); + sync_with_manager (); +} + +ExportMainDialog::FilePage::FilePage (Session * s, ManagerPtr profile_manager, ExportMainDialog * parent, uint32_t number, + ExportProfileManager::FormatStatePtr format_state, + ExportProfileManager::FilenameStatePtr filename_state) : + format_state (format_state), + filename_state (filename_state), + profile_manager (profile_manager), + + format_label (_("Format"), Gtk::ALIGN_LEFT), + filename_label (_("Location"), Gtk::ALIGN_LEFT), + tab_number (number) +{ + set_border_width (12); + + pack_start (format_label, false, false, 0); + pack_start (format_align, false, false, 0); + pack_start (filename_label, false, false, 0); + pack_start (filename_align, false, false, 0); + + format_align.add (format_selector); + format_align.set_padding (6, 12, 18, 0); + + filename_align.add (filename_selector); + filename_align.set_padding (0, 12, 18, 0); + + Pango::AttrList bold; + Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD); + bold.insert (b); + + format_label.set_attributes (bold); + filename_label.set_attributes (bold); + tab_label.set_attributes (bold); + + /* Set states */ + format_selector.set_state (format_state, s); + filename_selector.set_state (filename_state, s); + + /* Signals */ + + tab_close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*parent, &ExportMainDialog::remove_file_page), this)); + + profile_manager->FormatListChanged.connect (sigc::mem_fun (format_selector, &ExportFormatSelector::update_format_list)); + + format_selector.FormatEdited.connect (sigc::mem_fun (*this, &ExportMainDialog::FilePage::save_format_to_manager)); + format_selector.FormatRemoved.connect (sigc::mem_fun (*profile_manager, &ExportProfileManager::remove_format_profile)); + format_selector.NewFormat.connect (sigc::mem_fun (*profile_manager, &ExportProfileManager::get_new_format)); + + format_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::FilePage::update_tab_label)); + filename_selector.CriticalSelectionChanged.connect (CriticalSelectionChanged.make_slot()); + + /* Tab widget */ + + tab_close_button.add (*Gtk::manage (new Gtk::Image (::get_icon("close")))); + tab_close_alignment.add (tab_close_button); + tab_close_alignment.set (0.5, 0.5, 0, 0); + + tab_widget.pack_start (tab_label, false, false, 3); + tab_widget.pack_end (tab_close_alignment, false, false, 0); + tab_widget.show_all_children (); + update_tab_label (); + + /* Done */ + + show_all_children (); +} + +ExportMainDialog::FilePage::~FilePage () +{ +} + +void +ExportMainDialog::FilePage::set_remove_sensitive (bool value) +{ + tab_close_button.set_sensitive (value); +} + +Glib::ustring +ExportMainDialog::FilePage::get_format_name () const +{ + if (format_state && format_state->format) { + return format_state->format->name(); + } + return "No format!"; +} + +void +ExportMainDialog::FilePage::save_format_to_manager (FormatPtr format) +{ + profile_manager->save_format_to_disk (format); +} + +void +ExportMainDialog::FilePage::update_tab_label () +{ + tab_label.set_text (string_compose ("%1 %2", tab_number, get_format_name())); + CriticalSelectionChanged(); +} + +void +ExportMainDialog::add_new_file_page () +{ + FilePage * page; + if ((page = dynamic_cast (file_notebook.get_nth_page (file_notebook.get_current_page())))) { + add_file_page (profile_manager->duplicate_format_state (page->get_format_state()), + profile_manager->duplicate_filename_state (page->get_filename_state())); + } +} + +void +ExportMainDialog::add_file_page (ExportProfileManager::FormatStatePtr format_state, ExportProfileManager::FilenameStatePtr filename_state) +{ + FilePage * page = Gtk::manage (new FilePage (session, profile_manager, this, page_counter, format_state, filename_state)); + page->CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings)); + file_notebook.insert_page (*page, page->get_tab_widget(), file_notebook.get_n_pages() - 1); + + update_remove_file_page_sensitivity (); + file_notebook.show_all_children(); + ++page_counter; + + update_warnings (); +} + +void +ExportMainDialog::remove_file_page (FilePage * page) +{ + profile_manager->remove_format_state (page->get_format_state()); + profile_manager->remove_filename_state (page->get_filename_state()); + + file_notebook.remove_page (*page); + update_remove_file_page_sensitivity (); + + update_warnings (); +} + +void +ExportMainDialog::update_remove_file_page_sensitivity () +{ + FilePage * page; + if ((page = dynamic_cast (file_notebook.get_nth_page (0)))) { + if (file_notebook.get_n_pages() > 2) { + page->set_remove_sensitive (true); + } else { + page->set_remove_sensitive (false); + } + } +} + +void +ExportMainDialog::handle_page_change (GtkNotebookPage*, uint page) +{ + if (file_notebook.get_n_pages() == 2 && page == 0) { return; } + + if (page + 1 == (uint32_t) file_notebook.get_n_pages()) { + file_notebook.set_current_page (last_visible_page); + } else { + last_visible_page = page; + } +} + +void +ExportMainDialog::add_error (Glib::ustring const & text) +{ + fast_export_button->set_sensitive (false); + rt_export_button->set_sensitive (false); + + if (warn_string.empty()) { + warn_string = _("Error: ") + text + ""; + } else { + warn_string = _("Error: ") + text + "\n" + warn_string; + } + + warn_label.set_markup (warn_string); +} + +void +ExportMainDialog::add_warning (Glib::ustring const & text) +{ + if (warn_string.empty()) { + warn_string = _("Warning: ") + text + ""; + } else { + warn_string = warn_string + _("\nWarning: ") + text + ""; + } + + warn_label.set_markup (warn_string); +} diff --git a/gtk2_ardour/export_main_dialog.h b/gtk2_ardour/export_main_dialog.h new file mode 100644 index 0000000000..af795554e1 --- /dev/null +++ b/gtk2_ardour/export_main_dialog.h @@ -0,0 +1,234 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_main_dialog_h__ +#define __export_main_dialog_h__ + +#include +#include + +#include "public_editor.h" +#include "export_timespan_selector.h" +#include "export_channel_selector.h" +#include "export_format_selector.h" +#include "export_filename_selector.h" +#include "ardour_dialog.h" + +#include + +namespace ARDOUR { + class ExportFilename; + class ExportFormatSpecification; + class ExportChannelConfiguration; +} + +class ExportTimespanSelector; +class ExportChannelSelector; +class ExportFormatSelector; +class ExportFilenameSelector; + +class ExportMainDialog : public ArdourDialog { + + public: + + explicit ExportMainDialog (PublicEditor & editor); + ~ExportMainDialog (); + + void set_session (ARDOUR::Session* s); + + void select_timespan (Glib::ustring id); + + /* Responses */ + + enum Responses { + RESPONSE_RT, + RESPONSE_FAST, + RESPONSE_CANCEL + }; + + private: + + void close_dialog (); + + void sync_with_manager (); + void update_warnings (); + void show_conflicting_files (); + + typedef boost::shared_ptr TimespanPtr; + typedef boost::shared_ptr > TimespanList; + + typedef boost::shared_ptr ChannelConfigPtr; + typedef std::list ChannelConfigList; + + typedef boost::shared_ptr FilenamePtr; + + typedef boost::shared_ptr HandlerPtr; + typedef boost::shared_ptr FormatPtr; + typedef boost::shared_ptr ManagerPtr; + + void export_rt (); + void export_fw (); + + void show_progress (); + Glib::ustring get_nth_format_name (uint32_t n); + gint progress_timeout (); + + /* Other stuff */ + + PublicEditor & editor; + HandlerPtr handler; + ManagerPtr profile_manager; + + /*** GUI components ***/ + + Gtk::Table main_table; + + /* Presets */ + + typedef ARDOUR::ExportProfileManager::PresetPtr PresetPtr; + typedef ARDOUR::ExportProfileManager::PresetList PresetList; + + sigc::connection preset_select_connection; + + void select_preset (); + void save_current_preset (); + void remove_current_preset (); + + struct PresetCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn preset; + Gtk::TreeModelColumn label; + + PresetCols () { add (preset); add (label); } + }; + PresetCols preset_cols; + Glib::RefPtr preset_list; + PresetPtr current_preset; + PresetPtr previous_preset; + + Gtk::Alignment preset_align; + Gtk::HBox preset_hbox; + Gtk::Label preset_label; + Gtk::ComboBoxEntry preset_entry; + + Gtk::Button preset_save_button; + Gtk::Button preset_remove_button; + Gtk::Button preset_new_button; + + /* File Notebook */ + + class FilePage : public Gtk::VBox { + public: + FilePage (ARDOUR::Session * s, ManagerPtr profile_manager, ExportMainDialog * parent, uint32_t number, + ARDOUR::ExportProfileManager::FormatStatePtr format_state, + ARDOUR::ExportProfileManager::FilenameStatePtr filename_state); + + virtual ~FilePage (); + + Gtk::Widget & get_tab_widget () { return tab_widget; } + void set_remove_sensitive (bool value); + Glib::ustring get_format_name () const; + + ARDOUR::ExportProfileManager::FormatStatePtr get_format_state () const { return format_state; } + ARDOUR::ExportProfileManager::FilenameStatePtr get_filename_state () const { return filename_state; } + + sigc::signal CriticalSelectionChanged; + + private: + void save_format_to_manager (FormatPtr format); + void update_tab_label (); + + ARDOUR::ExportProfileManager::FormatStatePtr format_state; + ARDOUR::ExportProfileManager::FilenameStatePtr filename_state; + ManagerPtr profile_manager; + + /* GUI components */ + + Gtk::Label format_label; + Gtk::Alignment format_align; + ExportFormatSelector format_selector; + + Gtk::Label filename_label; + Gtk::Alignment filename_align; + ExportFilenameSelector filename_selector; + + Gtk::HBox tab_widget; + Gtk::Label tab_label; + Gtk::Alignment tab_close_alignment; + Gtk::Button tab_close_button; + uint32_t tab_number; + }; + + void add_new_file_page (); + void add_file_page (ARDOUR::ExportProfileManager::FormatStatePtr format_state, ARDOUR::ExportProfileManager::FilenameStatePtr filename_state); + void remove_file_page (FilePage * page); + void update_remove_file_page_sensitivity (); + void handle_page_change (GtkNotebookPage*, uint32_t page); + + uint32_t last_visible_page; + uint32_t page_counter; + + /* Warning area */ + + Gtk::VBox warn_container; + + Gtk::HBox warn_hbox; + Gtk::Label warn_label; + Glib::ustring warn_string; + + Gtk::HBox list_files_hbox; + Gtk::Label list_files_label; + Gtk::Button list_files_button; + Glib::ustring list_files_string; + + void add_error (Glib::ustring const & text); + void add_warning (Glib::ustring const & text); + + /* Progress bar */ + + Gtk::VBox progress_container; + Gtk::Label progress_label; + Gtk::ProgressBar progress_bar; + sigc::connection progress_connection; + + /* Everything else */ + + Gtk::Label timespan_label; + Gtk::Alignment timespan_align; + ExportTimespanSelector timespan_selector; + + Gtk::Label channels_label; + Gtk::Alignment channels_align; + ExportChannelSelector channel_selector; + + Gtk::Notebook file_notebook; + + Gtk::HBox new_file_hbox; + Gtk::Button new_file_button; + Gtk::VBox new_file_dummy; + + Gtk::Button * cancel_button; + Gtk::Button * rt_export_button; + Gtk::Button * fast_export_button; + +}; + +#endif /* __ardour_export_main_dialog_h__ */ diff --git a/gtk2_ardour/export_multiplicator.cc b/gtk2_ardour/export_multiplicator.cc new file mode 100644 index 0000000000..969548e273 --- /dev/null +++ b/gtk2_ardour/export_multiplicator.cc @@ -0,0 +1,330 @@ +/* This file is not used at the moment. It includes code related to export a + * multiplication graph system that can be used together with the code in + * libs/ardour/export_multiplication.cc and libs/ardour/ardour/export_multiplication.h + * - Sakari Bergen 6.8.2008 - + */ + +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_multiplicator.h" + +#include + +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; + +#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) + +ExportMultiplicator::ExportMultiplicator () : + graph (0) +{ + add (table); +} + +ExportMultiplicator::~ExportMultiplicator () +{} + +void +ExportMultiplicator::set_manager (boost::shared_ptr _manager) +{ + manager = _manager; + manager->GraphChanged.connect (sigc::mem_fun (*this, &ExportMultiplicator::redraw)); + + redraw(); +} + +void +ExportMultiplicator::redraw () +{ + if (!manager) { return; } + + graph = &manager->get_graph(); + + /* Empty table */ + + table.foreach (sigc::mem_fun (table, &Gtk::Table::remove)); + widget_map.clear(); + + /* Calculate table dimensions */ + + uint32_t max_width = 0; + GraphLevel max_level = NoLevel; + + if (graph->timespans.size() > max_width) { + max_width = graph->timespans.size(); + max_level = Timespans; + } + + if (graph->channel_configs.size() > max_width) { + max_width = graph->channel_configs.size(); + max_level = ChannelConfigs; + } + + if (graph->formats.size() > max_width) { + max_width = graph->formats.size(); + max_level = Formats; + } + + if (graph->filenames.size() > max_width) { + max_width = graph->filenames.size(); + max_level = Filenames; + } + + table.resize (4, max_width); + + std::cout << "Table width: " << max_width << std::endl; + + /* Fill table */ + + for (list::const_iterator it = graph->timespans.begin(); it != graph->timespans.end(); ++it) { + draw_timespan (*it, get_bounds (it->get(), Timespans, max_level)); + } + + for (list::const_iterator it = graph->channel_configs.begin(); it != graph->channel_configs.end(); ++it) { + draw_channel_config (*it, get_bounds (it->get(), ChannelConfigs, max_level)); + } + + for (list::const_iterator it = graph->formats.begin(); it != graph->formats.end(); ++it) { + draw_format (*it, get_bounds (it->get(), Formats, max_level)); + } + + for (list::const_iterator it = graph->filenames.begin(); it != graph->filenames.end(); ++it) { + draw_filename (*it, get_bounds (it->get(), Filenames, max_level)); + } + + show_all_children (); +} + +std::pair +ExportMultiplicator::get_bounds (ARDOUR::ExportProfileManager::GraphNode * node, GraphLevel current_level, GraphLevel max_level) const +{ + assert (current_level != NoLevel && max_level != NoLevel && graph); + + uint32_t left_bound = 0; + uint32_t right_bound = 0; + + bool left_bound_found = false; + + bool (ExportProfileManager::GraphNode::*relation_func) (ExportProfileManager::GraphNode const *) const; + if (max_level < current_level) { + std::cout << "using 'is_ancestor_of'" << std::endl; + relation_func = &ExportProfileManager::GraphNode::is_ancestor_of; + } else if (max_level > current_level) { + std::cout << "using 'is_descendant_of'" << std::endl; + relation_func = &ExportProfileManager::GraphNode::is_descendant_of; + } else { + std::cout << "using 'equals'" << std::endl; + relation_func = &ExportProfileManager::GraphNode::equals; + } + + switch (max_level) { + case Timespans: + for (list::const_iterator it = graph->timespans.begin(); it != graph->timespans.end(); ++it) { + if (CALL_MEMBER_FN(**it, relation_func) (node)) { + left_bound_found = true; + } else if (!left_bound_found) { + ++left_bound; + } + + if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) { + break; + } else { + ++right_bound; + } + } + break; + + case ChannelConfigs: + for (list::const_iterator it = graph->channel_configs.begin(); it != graph->channel_configs.end(); ++it) { + if (CALL_MEMBER_FN(**it, relation_func) (node)) { + left_bound_found = true; + } else if (!left_bound_found) { + ++left_bound; + } + + if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) { + break; + } else { + ++right_bound; + } + } + break; + + case Formats: + for (list::const_iterator it = graph->formats.begin(); it != graph->formats.end(); ++it) { + if (CALL_MEMBER_FN(**it, relation_func) (node)) { + left_bound_found = true; + } else if (!left_bound_found) { + ++left_bound; + } + + if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) { + break; + } else { + ++right_bound; + } + } + break; + + case Filenames: + for (list::const_iterator it = graph->filenames.begin(); it != graph->filenames.end(); ++it) { + if (CALL_MEMBER_FN(**it, relation_func) (node)) { + std::cout << "filename relation check returned true" << std::endl; + left_bound_found = true; + } else if (!left_bound_found) { + std::cout << "filename relation check returned false" << std::endl; + ++left_bound; + } + + if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) { + break; + } else { + ++right_bound; + } + } + break; + + case NoLevel: + // Not reached ! + break; + } + + return std::pair (left_bound, right_bound); +} + +void +ExportMultiplicator::draw_timespan (ARDOUR::ExportProfileManager::TimespanNodePtr node, std::pair bounds) +{ + ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Timespan %1", node->id()), manager, node.get())); + get_hbox (TablePosition (bounds.first, bounds.second, Timespans))->pack_end (*button, true, true); +} + +void +ExportMultiplicator::draw_channel_config (ARDOUR::ExportProfileManager::ChannelConfigNodePtr node, std::pair bounds) +{ + ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Channel config %1", node->id()), manager, node.get())); + get_hbox (TablePosition (bounds.first, bounds.second, ChannelConfigs))->pack_end (*button, true, true); +} + +void +ExportMultiplicator::draw_format (ARDOUR::ExportProfileManager::FormatNodePtr node, std::pair bounds) +{ + ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Format %1", node->id()), manager, node.get())); + get_hbox (TablePosition (bounds.first, bounds.second, Formats))->pack_end (*button, true, true); +} + +void +ExportMultiplicator::draw_filename (ARDOUR::ExportProfileManager::FilenameNodePtr node, std::pair bounds) +{ + ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Filename %1", node->id()), manager, node.get())); + get_hbox (TablePosition (bounds.first, bounds.second, Filenames))->pack_end (*button, true, true); +} + +boost::shared_ptr +ExportMultiplicator::get_hbox (TablePosition position) +{ + WidgetMap::iterator it = widget_map.find (position); + if (it != widget_map.end()) { return it->second; } + + boost::shared_ptr widget = widget_map.insert (WidgetPair (position, boost::shared_ptr (new Gtk::HBox ()))).first->second; + table.attach (*widget, position.left, position.right, position.row - 1, position.row); + + return widget; +} + +ExportMultiplicator::ButtonWidget::ButtonWidget (Glib::ustring name, boost::shared_ptr m, ExportProfileManager::GraphNode * node) : + label (name), + node (node), + split_position (0.5) +{ + manager = m; + + menu_actions = Gtk::ActionGroup::create(); + menu_actions->add (Gtk::Action::create ("Split", _("_Split here")), sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::split)); + menu_actions->add (Gtk::Action::create ("Remove", _("_Remove")), sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::remove)); + + ui_manager = Gtk::UIManager::create(); + ui_manager->insert_action_group (menu_actions); + + Glib::ustring ui_info = + "" + " " + " " + " " + " " + ""; + + ui_manager->add_ui_from_string (ui_info); + menu = dynamic_cast (ui_manager->get_widget ("/PopupMenu")); + + add_events (Gdk::BUTTON_PRESS_MASK); + signal_button_press_event ().connect (sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::on_button_press_event)); + + modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#0000")); + set_border_width (1); + vbox.pack_start (label, true, true, 4); + add (vbox); +} + +bool +ExportMultiplicator::ButtonWidget::on_button_press_event (GdkEventButton* event) +{ + if(event->type != GDK_BUTTON_PRESS) { return false; } + if (event->button == 1) { + node->select (!node->selected ()); + + if (node->selected ()) { + unset_bg (Gtk::STATE_NORMAL); + modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#194756")); + } else { + unset_bg (Gtk::STATE_NORMAL); + modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#0000")); + } + + return true; + + } else if (event->button == 3) { + int x, y; + get_pointer (x, y); + split_position = (float) x / get_width(); + + menu->popup (event->button, event->time); + return true; + } + + return false; +} + +void +ExportMultiplicator::ButtonWidget::split () +{ + manager->split_node (node, split_position); +} + +void +ExportMultiplicator::ButtonWidget::remove () +{ + manager->remove_node (node); +} diff --git a/gtk2_ardour/export_multiplicator.h b/gtk2_ardour/export_multiplicator.h new file mode 100644 index 0000000000..20ce96cda0 --- /dev/null +++ b/gtk2_ardour/export_multiplicator.h @@ -0,0 +1,121 @@ +/* This file is not used at the moment. It includes code related to export a + * multiplication graph system that can be used together with the code in + * libs/ardour/export_multiplication.cc and libs/ardour/ardour/export_multiplication.h + * - Sakari Bergen 6.8.2008 - + */ + +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_multiplicator_h__ +#define __export_multiplicator_h__ + +#include +#include + +#include + +#include +#include + +using std::list; +using ARDOUR::ExportProfileManager; + +class ExportMultiplicator : public Gtk::EventBox { + public: + + ExportMultiplicator (); + ~ExportMultiplicator (); + + void set_manager (boost::shared_ptr _manager); + + private: + + boost::shared_ptr manager; + ExportProfileManager::MultiplicationGraph const * graph; + + /* Drawing stuff */ + + Gtk::Table table; + + void redraw (); + + enum GraphLevel { + NoLevel = 0, + Timespans = 1, + ChannelConfigs = 2, + Formats = 3, + Filenames = 4 + }; + + std::pair get_bounds (ExportProfileManager::GraphNode * node, GraphLevel current_level, GraphLevel max_level) const; + + void draw_timespan (ExportProfileManager::TimespanNodePtr node, std::pair bounds); + void draw_channel_config (ExportProfileManager::ChannelConfigNodePtr node, std::pair bounds); + void draw_format (ExportProfileManager::FormatNodePtr node, std::pair bounds); + void draw_filename (ExportProfileManager::FilenameNodePtr node, std::pair bounds); + + struct TablePosition { + uint32_t left; + uint32_t right; + uint32_t row; + + TablePosition (uint32_t left, uint32_t right, uint32_t row) : + left (left), right (right), row (row) {} + + bool operator== (TablePosition const & other) const { return (row == other.row && left == other.left && right == other.right); } + bool operator< (TablePosition const & other) const { return (row < other.row || left < other.left || right < other.right); } + }; + + typedef std::map > WidgetMap; + typedef std::pair > WidgetPair; + + boost::shared_ptr get_hbox (TablePosition position); + WidgetMap widget_map; + + /* Button Widget */ + + class ButtonWidget : public Gtk::EventBox { + public: + ButtonWidget (Glib::ustring name, boost::shared_ptr m, ExportProfileManager::GraphNode * node); + + private: + + Gtk::Label label; + Gtk::VBox vbox; + + bool on_button_press_event (GdkEventButton* event); + + void split (); + void remove (); + + boost::shared_ptr manager; + ExportProfileManager::GraphNode * node; + float split_position; + + /* Context menu */ + + Glib::RefPtr menu_actions; + Glib::RefPtr ui_manager; + Gtk::Menu * menu; + }; +}; + +#endif /* __export_multiplicator_h__ */ diff --git a/gtk2_ardour/export_timespan_selector.cc b/gtk2_ardour/export_timespan_selector.cc new file mode 100644 index 0000000000..0f02a1580e --- /dev/null +++ b/gtk2_ardour/export_timespan_selector.cc @@ -0,0 +1,394 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "export_timespan_selector.h" + +#include "ardour_ui.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; + +ExportTimespanSelector::ExportTimespanSelector () : + time_format_label (_("Show Times as:"), Gtk::ALIGN_LEFT) +{ + + option_hbox.pack_start (time_format_label, false, false, 0); + option_hbox.pack_start (time_format_combo, false, false, 6); + + range_scroller.add (range_view); + range_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + + pack_start (option_hbox, false, false, 0); + pack_start (range_scroller, true, true, 6); + + /*** Combo boxes ***/ + + Gtk::TreeModel::iterator iter; + Gtk::TreeModel::Row row; + + /* Time format combo */ + + time_format_list = Gtk::ListStore::create (time_format_cols); + time_format_combo.set_model (time_format_list); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportProfileManager::SMPTE; + row[time_format_cols.label] = X_("Timecode"); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportProfileManager::MinSec; + row[time_format_cols.label] = _("Minutes:Seconds"); + + iter = time_format_list->append(); + row = *iter; + row[time_format_cols.format] = ExportProfileManager::BBT; + row[time_format_cols.label] = _("Bars:Beats"); + + time_format_combo.pack_start (time_format_cols.label); + time_format_combo.set_active (0); + + time_format_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportTimespanSelector::change_time_format)); + + /* Range view */ + + range_list = Gtk::ListStore::create (range_cols); + range_view.set_model (range_list); + range_view.set_headers_visible (false); + + range_view.append_column_editable ("", range_cols.selected); + range_view.append_column_editable ("", range_cols.name); + + Gtk::CellRendererText * label_render = Gtk::manage (new Gtk::CellRendererText()); + Gtk::TreeView::Column * label_col = Gtk::manage (new Gtk::TreeView::Column ("", *label_render)); + label_col->add_attribute (label_render->property_markup(), range_cols.label); + range_view.append_column (*label_col); + + if (Gtk::CellRendererToggle * renderer = dynamic_cast (range_view.get_column_cell_renderer (0))) { + renderer->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &ExportTimespanSelector::update_selection))); + } + if (Gtk::CellRendererText * renderer = dynamic_cast (range_view.get_column_cell_renderer (1))) { + renderer->signal_edited().connect (sigc::mem_fun (*this, &ExportTimespanSelector::update_range_name)); + } + +} + +ExportTimespanSelector::~ExportTimespanSelector () +{ + +} + +void +ExportTimespanSelector::set_state (ARDOUR::ExportProfileManager::TimespanStatePtr const state_, ARDOUR::Session * session_) +{ + state = state_; + session = session_; + + fill_range_list (); + set_selection_from_state (); + + CriticalSelectionChanged(); +} + +void +ExportTimespanSelector::select_one_range (Glib::ustring id) +{ + if (!state) { return; } + + range_view.remove_column (*range_view.get_column (0)); + + Glib::ustring real_id; + + if (!id.compare (X_("session"))) { + real_id = state->session_range->id().to_s(); + } else if (!id.compare (X_("selection"))) { + real_id = state->selection_range->id().to_s(); + } else { + real_id = id; + } + + for (Gtk::ListStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end();) { + if (!it->get_value (range_cols.location)->id().to_s().compare (real_id)) { + it->set_value (range_cols.selected, true); + ++it; + } else { + Gtk::ListStore::Children::iterator temp = it++; + range_list->erase (temp); + } + } + + int x_offset, y_offset, width, height; + Gtk::CellRenderer * renderer = *range_view.get_column(0)->get_cell_renderers().begin(); + renderer->get_size (range_view, x_offset, y_offset, width, height); + range_scroller.set_size_request (-1, height); + range_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER); + + update_selection(); +} + +void +ExportTimespanSelector::fill_range_list () +{ + range_list->clear(); + + Gtk::TreeModel::iterator iter; + Gtk::TreeModel::Row row; + for (LocationList::const_iterator it = state->ranges->begin(); it != state->ranges->end(); ++it) { + iter = range_list->append(); + row = *iter; + + row[range_cols.location] = *it; + row[range_cols.selected] = false; + row[range_cols.name] = (*it)->name(); + row[range_cols.label] = construct_label (*it); + } +} + +void +ExportTimespanSelector::set_selection_from_state () +{ + Gtk::TreeModel::Children::iterator tree_it; + + for (TimespanList::iterator it = state->timespans->begin(); it != state->timespans->end(); ++it) { + ustring id = (*it)->range_id(); + for (tree_it = range_list->children().begin(); tree_it != range_list->children().end(); ++tree_it) { + Location * loc = tree_it->get_value (range_cols.location); + + if ((!id.compare ("session") && loc == state->session_range.get()) || + (!id.compare ("selection") && loc == state->selection_range.get()) || + (!id.compare (loc->id().to_s()))) { + tree_it->set_value (range_cols.selected, true); + } + } + } + + for (tree_it = time_format_list->children().begin(); tree_it != time_format_list->children().end(); ++tree_it) { + if (tree_it->get_value (time_format_cols.format) == state->time_format) { + time_format_combo.set_active (tree_it); + } + } +} + +void +ExportTimespanSelector::update_selection () +{ + update_timespans (); + CriticalSelectionChanged (); +} + +void +ExportTimespanSelector::update_timespans () +{ + state->timespans->clear(); + + TimespanPtr span; + HandlerPtr handler = session->get_export_handler(); + + for (Gtk::TreeStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) { + if (it->get_value (range_cols.selected)) { + span = handler->add_timespan(); + Location * loc = it->get_value (range_cols.location); + + Glib::ustring id; + if (loc == state->session_range.get()) { + id = "session"; + } else if (loc == state->selection_range.get()) { + id = "selection"; + } else { + id = loc->id().to_s(); + } + + span->set_range (loc->start(), loc->end()); + span->set_name (loc->name()); + span->set_range_id (id); + state->timespans->push_back (span); + } + } +} + +void +ExportTimespanSelector::change_time_format () +{ + state->time_format = time_format_combo.get_active()->get_value (time_format_cols.format); + + for (Gtk::ListStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) { + Location * location = it->get_value (range_cols.location); + it->set_value (range_cols.label, construct_label (location)); + } +} + +Glib::ustring +ExportTimespanSelector::construct_label (ARDOUR::Location const * location) +{ + Glib::ustring label; + Glib::ustring start; + Glib::ustring end; + + nframes_t start_frame = location->start(); + nframes_t end_frame = location->end(); + + switch (state->time_format) { + case AudioClock::BBT: + start = bbt_str (start_frame); + end = bbt_str (end_frame); + break; + + case AudioClock::SMPTE: + start = smpte_str (start_frame); + end = smpte_str (end_frame); + break; + + case AudioClock::MinSec: + start = ms_str (start_frame); + end = ms_str (end_frame); + break; + + case AudioClock::Frames: + start = to_string (start_frame, std::dec); + end = to_string (end_frame, std::dec); + break; + + case AudioClock::Off: + break; + } + + // label += _("from "); + + // label += ""; + label += start; +// label += ""; + + label += _(" to "); + +// label += ""; + label += end; +// label += ""; + + return label; +} + + +Glib::ustring +ExportTimespanSelector::bbt_str (nframes_t frames) +{ + if (!session) { + return "Error!"; + } + + std::ostringstream oss; + BBT_Time time; + + session->bbt_time (frames, time); + + oss << std::setfill('0') << std::right << + std::setw(3) << + time.bars << "|" << + std::setw(2) << + time.beats << "|" << + std::setw(4) << + time.ticks; + + return oss.str(); +} + +Glib::ustring +ExportTimespanSelector::smpte_str (nframes_t frames) +{ + if (!session) { + return "Error!"; + } + + std::ostringstream oss; + SMPTE::Time time; + + session->smpte_time (frames, time); + + oss << std::setfill('0') << std::right << + std::setw(2) << + time.hours << ":" << + std::setw(2) << + time.minutes << ":" << + std::setw(2) << + time.seconds << ":" << + std::setw(2) << + time.frames; + + return oss.str(); +} + +Glib::ustring +ExportTimespanSelector::ms_str (nframes_t frames) +{ + if (!session) { + return "Error!"; + } + + std::ostringstream oss; + nframes_t left; + int hrs; + int mins; + int secs; + int sec_promilles; + + left = frames; + hrs = (int) floor (left / (session->frame_rate() * 60.0f * 60.0f)); + left -= (nframes_t) floor (hrs * session->frame_rate() * 60.0f * 60.0f); + mins = (int) floor (left / (session->frame_rate() * 60.0f)); + left -= (nframes_t) floor (mins * session->frame_rate() * 60.0f); + secs = (int) floor (left / (float) session->frame_rate()); + left -= (nframes_t) floor (secs * session->frame_rate()); + sec_promilles = (int) (left * 1000 / (float) session->frame_rate() + 0.5); + + oss << std::setfill('0') << std::right << + std::setw(2) << + hrs << ":" << + std::setw(2) << + mins << ":" << + std::setw(2) << + secs << "." << + std::setw(3) << + sec_promilles; + + return oss.str(); +} + +void +ExportTimespanSelector::update_range_name (Glib::ustring const & path, Glib::ustring const & new_text) +{ + Gtk::TreeStore::iterator it = range_list->get_iter (path); + it->get_value (range_cols.location)->set_name (new_text); + + CriticalSelectionChanged(); +} diff --git a/gtk2_ardour/export_timespan_selector.h b/gtk2_ardour/export_timespan_selector.h new file mode 100644 index 0000000000..757b2caad2 --- /dev/null +++ b/gtk2_ardour/export_timespan_selector.h @@ -0,0 +1,132 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __export_timespan_selector_h__ +#define __export_timespan_selector_h__ + +#include "public_editor.h" +#include "audio_clock.h" + +#include + +#include +#include + +#include +#include + +namespace ARDOUR { + class Location; + class ExportTimespan; + class ExportHandler; + class Session; +} + +using ARDOUR::CDMarkerFormat; + +/// +class ExportTimespanSelector : public Gtk::VBox { + private: + + typedef std::list LocationList; + typedef boost::shared_ptr HandlerPtr; + + typedef boost::shared_ptr TimespanPtr; + typedef std::list TimespanList; + typedef boost::shared_ptr TimespanListPtr; + + public: + + ExportTimespanSelector (); + ~ExportTimespanSelector (); + + void set_state (ARDOUR::ExportProfileManager::TimespanStatePtr const state_, ARDOUR::Session * session_); + + void select_one_range (Glib::ustring id); + + /* Compatibility with other elements */ + + sigc::signal CriticalSelectionChanged; + + private: + + void fill_range_list (); + void set_selection_from_state (); + + void update_selection (); + void update_timespans (); + + void change_time_format (); + + Glib::ustring construct_label (ARDOUR::Location const * location); + + Glib::ustring bbt_str (nframes_t frames); + Glib::ustring smpte_str (nframes_t frames); + Glib::ustring ms_str (nframes_t frames); + + void update_range_name (Glib::ustring const & path, Glib::ustring const & new_text); + + ARDOUR::Session * session; + + ARDOUR::ExportProfileManager::TimespanStatePtr state; + + /*** GUI components ***/ + + Gtk::HBox option_hbox; + Gtk::Label time_format_label; + + /* Time format */ + + typedef ARDOUR::ExportProfileManager::TimeFormat TimeFormat; + + struct TimeFormatCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn format; + Gtk::TreeModelColumn label; + + TimeFormatCols () { add(format); add(label); } + }; + TimeFormatCols time_format_cols; + Glib::RefPtr time_format_list; + Gtk::ComboBox time_format_combo; + + /* View */ + + struct RangeCols : public Gtk::TreeModelColumnRecord + { + public: + Gtk::TreeModelColumn location; + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn selected; + Gtk::TreeModelColumn name; + + RangeCols () { add (location); add(label); add(selected); add(name); } + }; + RangeCols range_cols; + + Glib::RefPtr range_list; + Gtk::TreeView range_view; + + Gtk::ScrolledWindow range_scroller; + +}; + +#endif /* __export_timespan_selector_h__ */ diff --git a/gtk2_ardour/session_metadata_dialog.cc b/gtk2_ardour/session_metadata_dialog.cc new file mode 100644 index 0000000000..35920038be --- /dev/null +++ b/gtk2_ardour/session_metadata_dialog.cc @@ -0,0 +1,738 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "session_metadata_dialog.h" + +#include + +#include +#include + +#include "i18n.h" +#include +#include +#include +#include + +#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) + +/*** MetadataField ***/ + +MetadataField::MetadataField (ustring const & field_name) : + _name (field_name) +{ +} + +MetadataField::~MetadataField() { } + +/* TextMetadataField */ + +TextMetadataField::TextMetadataField (Getter getter, Setter setter, ustring const & field_name, guint width ) : + MetadataField (field_name), + getter (getter), + setter (setter), + width (width) +{ + entry = 0; + label = 0; + value_label = 0; +} + +MetadataPtr +TextMetadataField::copy () +{ + return MetadataPtr (new TextMetadataField (getter, setter, _name, width)); +} + +void +TextMetadataField::save_data (ARDOUR::SessionMetadata & data) const +{ + CALL_MEMBER_FN (data, setter) (_value); +} + +void +TextMetadataField::load_data (ARDOUR::SessionMetadata const & data) +{ + _value = CALL_MEMBER_FN (data, getter) (); + if (entry) { + entry->set_text (_value); + } +} + +Gtk::Widget & +TextMetadataField::name_widget () +{ + label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT)); + return *label; +} + +Gtk::Widget & +TextMetadataField::value_widget () +{ + value_label = Gtk::manage (new Gtk::Label(_value)); + return *value_label; +} + +Gtk::Widget & +TextMetadataField::edit_widget () +{ + entry = Gtk::manage (new Gtk::Entry()); + + entry->set_text (_value); + entry->set_width_chars (width); + entry->signal_changed().connect (sigc::mem_fun(*this, &TextMetadataField::update_value)); + + return *entry; +} + +void +TextMetadataField::update_value () +{ + _value = entry->get_text (); +} + +/* NumberMetadataField */ + +NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, ustring const & field_name, guint numbers, guint width) : + MetadataField (field_name), + getter (getter), + setter (setter), + numbers (numbers), + width (width) +{ + entry = 0; + label = 0; + value_label = 0; +} + +MetadataPtr +NumberMetadataField::copy () +{ + return MetadataPtr (new NumberMetadataField (getter, setter, _name, numbers, width)); +} + +void +NumberMetadataField::save_data (ARDOUR::SessionMetadata & data) const +{ + uint32_t number = str_to_uint (_value); + CALL_MEMBER_FN (data, setter) (number); +} + +void +NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data) +{ + uint32_t number = CALL_MEMBER_FN (data, getter) (); + _value = uint_to_str (number); + if (entry) { + entry->set_text (_value); + } +} + +void +NumberMetadataField::update_value () +{ + // Accpt only numbers + uint32_t number = str_to_uint (entry->get_text()); + _value = uint_to_str (number); + entry->set_text (_value); +} + +Gtk::Widget & +NumberMetadataField::name_widget () +{ + label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT)); + return *label; +} + +Gtk::Widget & +NumberMetadataField::value_widget () +{ + value_label = Gtk::manage (new Gtk::Label(_value)); + return *value_label; +} + +Gtk::Widget & +NumberMetadataField::edit_widget () +{ + entry = Gtk::manage (new Gtk::Entry()); + + entry->set_text (_value); + entry->set_width_chars (width); + entry->set_max_length (numbers); + entry->signal_changed().connect (sigc::mem_fun(*this, &NumberMetadataField::update_value)); + + return *entry; +} + +ustring +NumberMetadataField::uint_to_str (uint32_t i) const +{ + std::ostringstream oss (""); + oss << i; + if (oss.str().compare("0")) { + return oss.str(); + } else { + return ""; + } +} + +uint32_t +NumberMetadataField::str_to_uint (ustring const & str) const +{ + ustring tmp (str); + ustring::size_type i; + while ((i = tmp.find_first_not_of("1234567890")) != ustring::npos) { + tmp.erase (i, 1); + } + + std::istringstream iss(tmp); + uint32_t result = 0; + iss >> result; + return result; +} + + +/* SessionMetadataSet */ + +SessionMetadataSet::SessionMetadataSet (ustring const & name) : + name (name) +{ + session = 0; +} + +void +SessionMetadataSet::add_data_field (MetadataPtr field) +{ + list.push_back (field); +} + +/* SessionMetadataSetEditable */ + +SessionMetadataSetEditable::SessionMetadataSetEditable (ustring const & name) : + SessionMetadataSet (name) +{ + table.set_row_spacings (6); + table.set_col_spacings (12); +} + +Gtk::Widget & +SessionMetadataSetEditable::get_tab_widget () +{ + tab_widget.set_text (name); + return tab_widget; +} + +void +SessionMetadataSetEditable::set_session (ARDOUR::Session * s) +{ + session = s; + + ARDOUR::SessionMetadata const & data = session->metadata(); + + table.resize (list.size(), 2); + uint32_t row = 0; + MetadataPtr field; + for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) { + field = *it; + field->load_data (data); + table.attach (field->name_widget(), 0, 1, row, row + 1); + table.attach (field->edit_widget(), 1, 2, row, row + 1); + ++row; + } +} + +void +SessionMetadataSetEditable::save_data () +{ + ARDOUR::SessionMetadata & data = session->metadata(); + for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) { + (*it)->save_data(data); + } +} + +/* SessionMetadataSetImportable */ + +SessionMetadataSetImportable::SessionMetadataSetImportable (ustring const & name) : + SessionMetadataSet (name), + session_list (list) +{ + tree = Gtk::ListStore::create (tree_cols); + tree_view.set_model (tree); + + Gtk::TreeView::Column * viewcol; + + // Add import column + Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle()); + import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed)); + viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render)); + viewcol->add_attribute (import_render->property_active(), tree_cols.import); + tree_view.append_column (*viewcol); + + // Add field name column + tree_view.append_column(_("Field"), tree_cols.field); + + // Add values column with pango markup + Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText()); + viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render)); + viewcol->add_attribute (values_render->property_markup(), tree_cols.values); + tree_view.append_column (*viewcol); + + select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all)); + + session = 0; +} + +Gtk::Widget & +SessionMetadataSetImportable::get_tab_widget () +{ + tab_widget.set_text (name); + return tab_widget; +} + +Gtk::Widget & +SessionMetadataSetImportable::get_select_all_widget () +{ + select_all_check.set_label (name); + return select_all_check; +} + +void +SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data) +{ + if (!session) { + std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl; + return; + } + + ARDOUR::SessionMetadata & session_data = session->metadata(); + + MetadataPtr session_field; + MetadataPtr import_field; + DataList::iterator session_it; + DataList::iterator import_it; + + // Copy list and load data to import + for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) { + session_field = *session_it; + session_field->load_data(session_data); + import_list.push_back (session_field->copy()); + } + + // Fill widget + session_it = session_list.begin(); + import_it = import_list.begin(); + while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same... + session_field = *session_it; + import_field = *import_it; + + import_field->load_data(data); // hasn't been done yet + + // Make string for values TODO get color from somewhere? + ustring values = "" + session_field->value() + "\n" + + "" + import_field->value() + ""; + + Gtk::TreeModel::iterator row_iter = tree->append(); + Gtk::TreeModel::Row row = *row_iter; + + row[tree_cols.field] = import_field->name(); + row[tree_cols.values] = values; + row[tree_cols.import] = false; + row[tree_cols.data] = import_field; + + ++session_it; + ++import_it; + } +} + +void +SessionMetadataSetImportable::save_data () +{ + if (!session) { + std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl; + return; + } + + ARDOUR::SessionMetadata & session_data = session->metadata(); + + Gtk::TreeModel::Children fields = tree->children(); + Gtk::TreeModel::Children::iterator it; + for (it = fields.begin(); it != fields.end(); ++it) { + if ((*it)[tree_cols.import]) { + MetadataPtr field = (*it)[tree_cols.data]; + field->save_data (session_data); + } + } +} + +void +SessionMetadataSetImportable::select_all () +{ + select_all_check.set_inconsistent (false); + bool state = select_all_check.get_active(); + + Gtk::TreeModel::Children fields = tree->children(); + Gtk::TreeModel::Children::iterator it; + for (it = fields.begin(); it != fields.end(); ++it) { + (*it)[tree_cols.import] = state; + } +} + +void +SessionMetadataSetImportable::selection_changed (ustring const & path) +{ + select_all_check.set_inconsistent (true); + + Gtk::TreeModel::iterator iter = tree->get_iter (path); + bool value((*iter)[tree_cols.import]); + (*iter)[tree_cols.import] = !value; +} + +/* SessionMetadataDialog */ + +template +SessionMetadataDialog::SessionMetadataDialog (ustring const & name) : + ArdourDialog (name, true) +{ + cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + cancel_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::end_dialog)); + save_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); + save_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::save_and_close)); +} + +template +void +SessionMetadataDialog::init_data () +{ + if (!session) { + std::cerr << "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl; + return; + } + + init_track_data (); + init_album_data (); + init_people_data (); + + for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) { + (*it)->set_session (session); + + notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget()); + } +} + +template +void +SessionMetadataDialog::load_extra_data (ARDOUR::SessionMetadata const & data) +{ + for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) { + (*it)->load_extra_data (data); + } +} + +template +void +SessionMetadataDialog::save_data () +{ + for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) { + (*it)->save_data (); + } +} + +template +void +SessionMetadataDialog::save_and_close () +{ + save_data (); + end_dialog (); +} + +template +void +SessionMetadataDialog::end_dialog () +{ + hide_all(); +} + +template +void +SessionMetadataDialog::warn_user (ustring const & string) +{ + Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true); + msg.run(); +} + +template +boost::shared_ptr > +SessionMetadataDialog::get_custom_widgets (WidgetFunc f) +{ + WidgetListPtr list (new WidgetList); + for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) + { + DataSet * set = dynamic_cast (it->get()); + list->push_back (& CALL_MEMBER_FN (*set, f) ()); + } + + return list; +} + +template +void +SessionMetadataDialog::add_widget (Gtk::Widget & widget) +{ + get_vbox()->pack_start (widget, true, true, 0); +} + +template +void +SessionMetadataDialog::init_track_data () +{ + DataSetPtr data_set (new DataSet (_("Track"))); + data_list.push_back (data_set); + + MetadataPtr ptr; + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3)); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright"))); + data_set->add_data_field (ptr); +} + +template +void +SessionMetadataDialog::init_album_data () +{ + DataSetPtr data_set (new DataSet (_("Album"))); + data_list.push_back (data_set); + + MetadataPtr ptr; + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4)); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3)); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2)); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2)); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC"))); + data_set->add_data_field (ptr); +} + +template +void +SessionMetadataDialog::init_people_data () +{ + DataSetPtr data_set (new DataSet (_("People"))); + data_list.push_back (data_set); + + MetadataPtr ptr; + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer"))); + data_set->add_data_field (ptr); + + ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, _("Mixer"))); + data_set->add_data_field (ptr); +} + +/* SessionMetadataEditor */ + +SessionMetadataEditor::SessionMetadataEditor () : + SessionMetadataDialog (_("Edit session metadata")) +{ + +} + +SessionMetadataEditor::~SessionMetadataEditor () +{ + // Remove pages from notebook to get rid of gsignal runtime warnings + notebook.pages().clear(); +} + +void +SessionMetadataEditor::run () +{ + init_data (); + init_gui(); + + ArdourDialog::run(); +} + +void +SessionMetadataEditor::init_gui () +{ + add_widget (notebook); + + show_all(); +} + +/* SessionMetadataImporter */ + +SessionMetadataImporter::SessionMetadataImporter () : + SessionMetadataDialog (_("Import session metadata")) +{ + +} + +SessionMetadataImporter::~SessionMetadataImporter () +{ + // Remove pages from notebook to get rid of gsignal runtime warnings + notebook.pages().clear(); +} + +void +SessionMetadataImporter::run () +{ + if (!session) { + std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl; + return; + } + + /* Open session file selector */ + + Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN); + session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT); + session_selector.set_default_response(Gtk::RESPONSE_ACCEPT); + + Gtk::FileFilter session_filter; + session_filter.add_pattern ("*.ardour"); + session_filter.set_name (_("Ardour sessions")); + session_selector.add_filter (session_filter); + session_selector.set_filter (session_filter); + + int response = session_selector.run(); + session_selector.hide (); + + switch (response) { + case Gtk::RESPONSE_ACCEPT: + break; + default: + return; + } + + string session_path = session_selector.get_filename(); + string path, name; + bool isnew; + + if (session_path.length() > 0) { + if (ARDOUR::find_session (session_path, path, name, isnew) != 0) { + return; + } + } else { + return; + } + + /* We have a session: load the data and run dialog */ + + string filename = Glib::build_filename (path, name + ".ardour"); + XMLTree session_tree; + if (!session_tree.read (filename)) { + warn_user (_("A proper ardour session file was not selected!")); + return; + } + + XMLNode * node = session_tree.root()->child ("Metadata"); + + if (!node) { + warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?")); + return; + } + + ARDOUR::SessionMetadata data; + data.set_state (*node); + + init_data (); + load_extra_data (data); + init_gui(); + + ArdourDialog::run(); +} + +void +SessionMetadataImporter::init_gui () +{ + // Select all from -widget + add_widget (selection_hbox); + selection_label.set_text (_("Import all from:")); + selection_hbox.pack_start (selection_label, false, false); + + WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget); + for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) { + selection_hbox.pack_start (**it, false, false, 6); + } + + add_widget (notebook); + + show_all(); +} diff --git a/gtk2_ardour/session_metadata_dialog.h b/gtk2_ardour/session_metadata_dialog.h new file mode 100644 index 0000000000..ffbb7a0930 --- /dev/null +++ b/gtk2_ardour/session_metadata_dialog.h @@ -0,0 +1,276 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + 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., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __session_metadata_dialog_h__ +#define __session_metadata_dialog_h__ + +#include "ardour_dialog.h" + +#include +#include + +#include +#include + +#include + +using std::string; +using Glib::ustring; + +class MetadataField; +typedef boost::shared_ptr MetadataPtr; + +/// Wraps a metadata field to be used in a GUI +class MetadataField { + public: + MetadataField (ustring const & field_name); + virtual ~MetadataField(); + virtual MetadataPtr copy () = 0; + + virtual void save_data (ARDOUR::SessionMetadata & data) const = 0; + virtual void load_data (ARDOUR::SessionMetadata const & data) = 0; + + virtual ustring name() { return _name; } + virtual ustring value() { return _value; } + + /// Get widget containing name of field + virtual Gtk::Widget & name_widget () = 0; + /// Get label containing value of field + virtual Gtk::Widget & value_widget () = 0; + /// Get widget for editing value + virtual Gtk::Widget & edit_widget () = 0; + protected: + ustring _name; + ustring _value; +}; + +/// MetadataField that contains text +class TextMetadataField : public MetadataField { + private: + typedef ustring (ARDOUR::SessionMetadata::*Getter) () const; + typedef void (ARDOUR::SessionMetadata::*Setter) (ustring const &); + public: + TextMetadataField (Getter getter, Setter setter, ustring const & field_name, guint width = 50); + MetadataPtr copy (); + + void save_data (ARDOUR::SessionMetadata & data) const; + void load_data (ARDOUR::SessionMetadata const & data); + + Gtk::Widget & name_widget (); + Gtk::Widget & value_widget (); + Gtk::Widget & edit_widget (); + private: + void update_value (); + + Getter getter; + Setter setter; + + Gtk::Label* label; + Gtk::Label* value_label; + Gtk::Entry* entry; + + uint width; +}; + +/// MetadataField that accepts only numbers +class NumberMetadataField : public MetadataField { + private: + typedef uint32_t (ARDOUR::SessionMetadata::*Getter) () const; + typedef void (ARDOUR::SessionMetadata::*Setter) (uint32_t); + public: + NumberMetadataField (Getter getter, Setter setter, ustring const & field_name, guint numbers, guint width = 50); + MetadataPtr copy (); + + void save_data (ARDOUR::SessionMetadata & data) const; + void load_data (ARDOUR::SessionMetadata const & data); + + Gtk::Widget & name_widget (); + Gtk::Widget & value_widget (); + Gtk::Widget & edit_widget (); + private: + void update_value (); + ustring uint_to_str (uint32_t i) const; + uint32_t str_to_uint (ustring const & str) const; + + Getter getter; + Setter setter; + + Gtk::Label* label; + Gtk::Label* value_label; + Gtk::Entry* entry; + + guint numbers; + guint width; +}; + +/// Interface for MetadataFields +class SessionMetadataSet { + public: + SessionMetadataSet (ustring const & name); + virtual ~SessionMetadataSet () {}; + + void add_data_field (MetadataPtr field); + + /// Sets session, into which the data is eventually saved + virtual void set_session (ARDOUR::Session * s) { session = s; } + /// allows loading extra data into data sets (for importing etc.) + virtual void load_extra_data (ARDOUR::SessionMetadata const & data) { } + /// Saves data to session + virtual void save_data () = 0; + + virtual Gtk::Widget & get_widget () = 0; + virtual Gtk::Widget & get_tab_widget () = 0; + + protected: + typedef std::list DataList; + DataList list; + ustring name; + ARDOUR::Session *session; +}; + +/// Contains MetadataFields for editing +class SessionMetadataSetEditable : public SessionMetadataSet { + public: + SessionMetadataSetEditable (ustring const & name); + + Gtk::Widget & get_widget () { return table; } + Gtk::Widget & get_tab_widget (); + + /// Sets session and loads data + void set_session (ARDOUR::Session * s); + /// Saves from MetadataFields into data + void save_data (); + + private: + Gtk::Table table; + Gtk::Label tab_widget; +}; + +/// Contains MetadataFields for importing +class SessionMetadataSetImportable : public SessionMetadataSet { + public: + SessionMetadataSetImportable (ustring const & name); + + Gtk::Widget & get_widget () { return tree_view; } + Gtk::Widget & get_tab_widget (); + Gtk::Widget & get_select_all_widget (); + + /// Loads importable data from data + void load_extra_data (ARDOUR::SessionMetadata const & data); + /// Saves from importable data (see load_data) to session_data + void save_data (); + + private: + DataList & session_list; // References MetadataSet::list + DataList import_list; + + struct Columns : public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn field; + Gtk::TreeModelColumn values; + Gtk::TreeModelColumn import; + Gtk::TreeModelColumn data; + + Columns() { add (field); add (values); add (import); add (data); } + }; + + Glib::RefPtr tree; + Columns tree_cols; + Gtk::TreeView tree_view; + + Gtk::Label tab_widget; + Gtk::CheckButton select_all_check; + + void select_all (); + void selection_changed (ustring const & path); +}; + +/// Metadata dialog interface +/** + * The DataSets are initalized in this class so that all + * Dialogs have the same sets of data in the same order. + */ +template +class SessionMetadataDialog : public ArdourDialog +{ + public: + SessionMetadataDialog (ustring const & name); + + protected: + void init_data (); + void load_extra_data (ARDOUR::SessionMetadata const & data); + void save_data (); + + virtual void init_gui () = 0; + virtual void save_and_close (); + virtual void end_dialog (); + + void warn_user (ustring const & string); + + typedef std::list WidgetList; + typedef boost::shared_ptr WidgetListPtr; + typedef Gtk::Widget & (DataSet::*WidgetFunc) (); + + /// Returns list of widgets gathered by calling f for each data set + WidgetListPtr get_custom_widgets (WidgetFunc f); + + /// Adds a widget to the table (vertical stacking) with automatic spacing + void add_widget (Gtk::Widget & widget); + + Gtk::Notebook notebook; + + private: + void init_track_data (); + void init_album_data (); + void init_people_data (); + + typedef boost::shared_ptr DataSetPtr; + typedef std::list DataSetList; + DataSetList data_list; + + Gtk::Button * save_button; + Gtk::Button * cancel_button; +}; + +class SessionMetadataEditor : public SessionMetadataDialog { + public: + SessionMetadataEditor (); + ~SessionMetadataEditor (); + void run (); + private: + void init_gui (); +}; + +class SessionMetadataImporter : public SessionMetadataDialog { + public: + SessionMetadataImporter (); + ~SessionMetadataImporter (); + void run (); + + private: + void init_gui (); + + // Select all from -widget + Gtk::HBox selection_hbox; + Gtk::Label selection_label; + +}; + +#endif diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 511697cf72..f1d5eb1c67 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -1046,8 +1046,9 @@ TimeAxisView::compute_controls_size_info () Gtk::Table one_row_table (1, 8); Button* buttons[5]; const int border_width = 2; - const int extra_height = (2 * border_width) + 2 // 2 pixels for the controls frame - + 10; // resizer button + const int extra_height = (2 * border_width) + + 2 // 2 pixels for the hseparator between TimeAxisView control areas + + 10; // resizer button (3 x 2 pixel elements + 2 x 2 pixel gaps) window.add (one_row_table); @@ -1087,9 +1088,11 @@ TimeAxisView::compute_controls_size_info () two_row_table.show_all (); req = two_row_table.size_request (); + cerr << "Normal height is " << req.height << " + " << extra_height << endl; + // height required to show all normal buttons - hNormal = req.height + extra_height; + hNormal = /*req.height*/ 48 + extra_height; // these heights are all just larger than normal. no more // elements are visible (yet). @@ -1182,6 +1185,8 @@ TimeAxisView::covers_y_position (double y) return 0; } + cerr << name() << " check for " << y << " within " << y_position << " and + " << height << endl; + if (y_position <= y && y < (y_position + height)) { return this; } -- cgit v1.2.3