new files from sakari, missed last time

git-svn-id: svn://localhost/ardour2/branches/3.0@3738 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2008-09-17 12:56:00 +00:00
parent 8876b57b0f
commit b5a57cc78c
17 changed files with 5425 additions and 3 deletions

View File

@ -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 <algorithm>
#include <pbd/convert.h>
#include <ardour/audioengine.h>
#include <ardour/export_channel_configuration.h>
#include <ardour/export_handler.h>
#include <ardour/io.h>
#include <ardour/route.h>
#include <ardour/audio_port.h>
#include <ardour/session.h>
#include <sstream>
#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<uint32_t> (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<Channel>::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<Gtk::CellRendererToggle *>(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<Gtk::ListStore> port_list = r_it->get_value (route_cols.port_list_col);
std::set<AudioPort *> route_ports;
std::set<AudioPort *> intersection;
std::map<AudioPort *, ustring> 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<AudioPort*, ustring> ((*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<std::set<AudioPort *> > (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<AudioPort *, ustring>::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<Gtk::ListStore> 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<ExportChannel> 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<Gtk::ListStore> 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<Gtk::ListStore> 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 ();
}

View File

@ -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 <list>
#include <ardour/export_profile_manager.h>
#include <gtkmm.h>
#include <sigc++/signal.h>
#include <boost/shared_ptr.hpp>
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<ARDOUR::ExportChannelConfiguration> ChannelConfigPtr;
typedef boost::shared_ptr<ARDOUR::ExportHandler> HandlerPtr;
public:
ExportChannelSelector ();
~ExportChannelSelector ();
void set_state (ARDOUR::ExportProfileManager::ChannelConfigStatePtr const state_, ARDOUR::Session * session_);
sigc::signal<void> CriticalSelectionChanged;
private:
void fill_route_list ();
void update_channel_count ();
void update_split_state ();
typedef boost::shared_ptr<ARDOUR::ExportChannel> ChannelPtr;
typedef std::list<ChannelPtr> 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<bool> selected;
Gtk::TreeModelColumn<Glib::ustring> name;
Gtk::TreeModelColumn<ARDOUR::IO *> io;
/* Combo list column (shared by all channels) */
typedef Gtk::TreeModelColumn<Glib::RefPtr<Gtk::ListStore> > 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<ARDOUR::AudioPort *> port;
Gtk::TreeModelColumn<Glib::ustring> label;
};
std::list<Channel> 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<bool> selected; // not used ATM
Gtk::TreeModelColumn<ARDOUR::AudioPort *> port;
Gtk::TreeModelColumn<Glib::ustring> 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<void> 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<Gtk::ListStore> 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__ */

View File

@ -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 <ardour/export_handler.h>
#include <ardour/session.h>
#include <ardour/session_directory.h>
#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();
}

View File

@ -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 <gtkmm.h>
#include <ardour/export_profile_manager.h>
#include <ardour/export_filename.h>
namespace ARDOUR {
class Session;
}
///
class ExportFilenameSelector : public Gtk::VBox {
public:
typedef boost::shared_ptr<ARDOUR::ExportFilename> FilenamePtr;
ExportFilenameSelector ();
~ExportFilenameSelector ();
void set_state (ARDOUR::ExportProfileManager::FilenameStatePtr state_, ARDOUR::Session * session_);
/* Compatibility with other elements */
sigc::signal<void> 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<ARDOUR::ExportFilename> filename;
Glib::RefPtr<Gtk::SizeGroup> 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<DateFormat> format;
Gtk::TreeModelColumn<Glib::ustring> label;
DateFormatCols () { add(format); add(label); }
};
DateFormatCols date_format_cols;
Glib::RefPtr<Gtk::ListStore> date_format_list;
Gtk::ComboBox date_format_combo;
/* Time combo */
typedef ARDOUR::ExportFilename::TimeFormat TimeFormat;
struct TimeFormatCols : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<TimeFormat> format;
Gtk::TreeModelColumn<Glib::ustring> label;
TimeFormatCols () { add(format); add(label); }
};
TimeFormatCols time_format_cols;
Glib::RefPtr<Gtk::ListStore> time_format_list;
Gtk::ComboBox time_format_combo;
};
#endif /* __export_filename_selector_h__ */

View File

@ -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 <ardour/session.h>
#include <ardour/export_format_specification.h>
#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<Gtk::CellRendererToggle *>(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<HasSampleFormat> hsf;
if (hsf = boost::dynamic_pointer_cast<HasSampleFormat> (*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<Gtk::CellRendererText*> (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<Gtk::CellRendererText*> (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<Gtk::CellRendererText*> (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<Gtk::CellRendererText*> (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<Gtk::CellRendererText*> (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<QualityCols> (quality_list, quality_view, quality_cols);
}
void
ExportFormatDialog::update_format_selection ()
{
update_selection<FormatCols> (format_list, format_view, format_cols);
}
void
ExportFormatDialog::update_sample_rate_selection ()
{
update_selection<SampleRateCols> (sample_rate_list, sample_rate_view, sample_rate_cols);
}
void
ExportFormatDialog::update_sample_format_selection ()
{
update_selection<SampleFormatCols> (sample_format_list, sample_format_view, sample_format_cols);
}
void
ExportFormatDialog::update_dither_type_selection ()
{
update_selection<DitherTypeCols> (dither_type_list, dither_type_view, dither_type_cols);
}
template<typename ColsT>
void
ExportFormatDialog::update_selection (Glib::RefPtr<Gtk::ListStore> & list, Gtk::TreeView & view, ColsT & cols)
{
if (applying_changes_from_engine) {
return;
}
Gtk::ListStore::Children::iterator it;
Glib::RefPtr<Gtk::TreeSelection> 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<ExportFormatManager::QualityState, QualityCols> (select, quality, quality_list, quality_view, quality_cols);
}
void
ExportFormatDialog::change_format_selection (bool select, WeakFormatPtr format)
{
change_selection<ExportFormat, FormatCols> (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<ExportFormatManager::SampleRateState, SampleRateCols> (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<HasSampleFormat::SampleFormatState, SampleFormatCols> (select, format, sample_format_list, sample_format_view, sample_format_cols);
}
void
ExportFormatDialog::change_dither_type_selection (bool select, WeakDitherTypePtr type)
{
change_selection<HasSampleFormat::DitherTypeState, DitherTypeCols> (select, type, dither_type_list, dither_type_view, dither_type_cols);
}
template<typename T, typename ColsT>
void
ExportFormatDialog::change_selection (bool select, boost::weak_ptr<T> w_ptr, Glib::RefPtr<Gtk::ListStore> & list, Gtk::TreeView & view, ColsT & cols)
{
++applying_changes_from_engine;
boost::shared_ptr<T> ptr = w_ptr.lock();
Gtk::ListStore::Children::iterator it;
Glib::RefPtr<Gtk::TreeSelection> 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<ExportFormatManager::QualityState, QualityCols> (compatibility, quality, quality_list, quality_cols);
}
void
ExportFormatDialog::change_format_compatibility (bool compatibility, WeakFormatPtr format)
{
change_compatibility<ExportFormat, FormatCols> (compatibility, format, format_list, format_cols);
}
void
ExportFormatDialog::change_sample_rate_compatibility (bool compatibility, WeakSampleRatePtr rate)
{
change_compatibility<ExportFormatManager::SampleRateState, SampleRateCols> (compatibility, rate, sample_rate_list, sample_rate_cols);
}
void
ExportFormatDialog::change_sample_format_compatibility (bool compatibility, WeakSampleFormatPtr format)
{
change_compatibility<HasSampleFormat::SampleFormatState, SampleFormatCols> (compatibility, format, sample_format_list, sample_format_cols);
}
void
ExportFormatDialog::change_dither_type_compatibility (bool compatibility, WeakDitherTypePtr type)
{
change_compatibility<HasSampleFormat::DitherTypeState, DitherTypeCols> (compatibility, type, dither_type_list, dither_type_cols, "red");
}
template<typename T, typename ColsT>
void
ExportFormatDialog::change_compatibility (bool compatibility, boost::weak_ptr<T> w_ptr, Glib::RefPtr<Gtk::ListStore> & list, ColsT & cols,
Glib::ustring const & c_incompatible, Glib::ustring const & c_compatible)
{
boost::shared_ptr<T> 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<ARDOUR::ExportFormatLinear> linear_ptr;
boost::shared_ptr<ARDOUR::ExportFormatOggVorbis> ogg_ptr;
boost::shared_ptr<ARDOUR::ExportFormatFLAC> flac_ptr;
boost::shared_ptr<ARDOUR::ExportFormatBWF> bwf_ptr;
if (linear_ptr = boost::dynamic_pointer_cast<ExportFormatLinear> (ptr)) {
show_linear_enconding_options (linear_ptr);
} else if (ogg_ptr = boost::dynamic_pointer_cast<ExportFormatOggVorbis> (ptr)) {
show_ogg_enconding_options (ogg_ptr);
} else if (flac_ptr = boost::dynamic_pointer_cast<ExportFormatFLAC> (ptr)) {
show_flac_enconding_options (flac_ptr);
} else if (bwf_ptr = boost::dynamic_pointer_cast<ExportFormatBWF> (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<ARDOUR::ExportFormatLinear> 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<HasSampleFormat> (ptr));
show_all_children ();
}
void
ExportFormatDialog::show_ogg_enconding_options (boost::shared_ptr<ARDOUR::ExportFormatOggVorbis> 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<ARDOUR::ExportFormatFLAC> 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<HasSampleFormat> (ptr));
show_all_children ();
}
void
ExportFormatDialog::show_bwf_enconding_options (boost::shared_ptr<ARDOUR::ExportFormatBWF> 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<HasSampleFormat> (ptr));
show_all_children ();
}
void
ExportFormatDialog::fill_sample_format_lists (boost::shared_ptr<ARDOUR::HasSampleFormat> 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);
}

View File

@ -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 <ardour/types.h>
#include <ardour/export_format_manager.h>
#include <ardour/export_format_compatibility.h>
#include <ardour/export_formats.h>
#include <pbd/xml++.h>
#include "ardour_dialog.h"
#include "audio_clock.h"
#include <gtkmm.h>
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<ARDOUR::ExportFormatSpecification> 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<typename ColsT>
void update_selection (Glib::RefPtr<Gtk::ListStore> & 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<typename T, typename ColsT>
void change_selection (bool select, boost::weak_ptr<T> w_ptr, Glib::RefPtr<Gtk::ListStore> & 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<typename T, typename ColsT>
void change_compatibility (bool compatibility, boost::weak_ptr<T> w_ptr, Glib::RefPtr<Gtk::ListStore> & 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<ARDOUR::ExportFormatLinear> ptr);
void show_ogg_enconding_options (boost::shared_ptr<ARDOUR::ExportFormatOggVorbis> ptr);
void show_flac_enconding_options (boost::shared_ptr<ARDOUR::ExportFormatFLAC> ptr);
void show_bwf_enconding_options (boost::shared_ptr<ARDOUR::ExportFormatBWF> ptr);
void fill_sample_format_lists (boost::shared_ptr<ARDOUR::HasSampleFormat> 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<ARDOUR::ExportFormatManager::CompatPtr> ptr;
Gtk::TreeModelColumn<bool> selected;
Gtk::TreeModelColumn<Glib::ustring> label;
CompatibilityCols () { add(ptr); add(selected); add(label); }
};
CompatibilityCols compatibility_cols;
Glib::RefPtr<Gtk::ListStore> 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<ARDOUR::ExportFormatManager::QualityPtr> ptr;
Gtk::TreeModelColumn<Glib::ustring> color;
Gtk::TreeModelColumn<Glib::ustring> label;
QualityCols () { add(ptr); add(color); add(label); }
};
QualityCols quality_cols;
Glib::RefPtr<Gtk::ListStore> quality_list;
struct FormatCols : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<ARDOUR::ExportFormatManager::FormatPtr> ptr;
Gtk::TreeModelColumn<Glib::ustring> color;
Gtk::TreeModelColumn<Glib::ustring> label;
FormatCols () { add(ptr); add(color); add(label); }
};
FormatCols format_cols;
Glib::RefPtr<Gtk::ListStore> format_list;
struct SampleRateCols : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<ARDOUR::ExportFormatManager::SampleRatePtr> ptr;
Gtk::TreeModelColumn<Glib::ustring> color;
Gtk::TreeModelColumn<Glib::ustring> label;
SampleRateCols () { add(ptr); add(color); add(label); }
};
SampleRateCols sample_rate_cols;
Glib::RefPtr<Gtk::ListStore> 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<ARDOUR::ExportFormatBase::SRCQuality> id;
Gtk::TreeModelColumn<Glib::ustring> label;
SRCQualityCols () { add(id); add(label); }
};
SRCQualityCols src_quality_cols;
Glib::RefPtr<Gtk::ListStore> 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<ARDOUR::HasSampleFormat::SampleFormatPtr> ptr;
Gtk::TreeModelColumn<Glib::ustring> color;
Gtk::TreeModelColumn<Glib::ustring> label;
SampleFormatCols () { add(ptr); add(color); add(label); }
};
SampleFormatCols sample_format_cols;
Glib::RefPtr<Gtk::ListStore> sample_format_list;
struct DitherTypeCols : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<ARDOUR::HasSampleFormat::DitherTypePtr> ptr;
Gtk::TreeModelColumn<Glib::ustring> color;
Gtk::TreeModelColumn<Glib::ustring> label;
DitherTypeCols () { add(ptr); add (color); add(label); }
};
DitherTypeCols dither_type_cols;
Glib::RefPtr<Gtk::ListStore> 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__ */

View File

@ -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 <ardour/export_format_specification.h>
#include <ardour/export_profile_manager.h>
#include <ardour/session.h>
#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());
}

View File

@ -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 <ardour/export_profile_manager.h>
#include <gtkmm.h>
#include <sigc++/signal.h>
#include <boost/shared_ptr.hpp>
namespace ARDOUR {
class Session;
class ExportFormatSpecification;
class ExportProfileManager;
}
///
class ExportFormatSelector : public Gtk::HBox {
private:
typedef boost::shared_ptr<ARDOUR::ExportFormatSpecification> FormatPtr;
typedef std::list<FormatPtr> FormatList;
public:
ExportFormatSelector ();
~ExportFormatSelector ();
void set_state (ARDOUR::ExportProfileManager::FormatStatePtr state_, ARDOUR::Session * session_);
void update_format_list ();
sigc::signal<void, FormatPtr> FormatEdited;
sigc::signal<void, FormatPtr> FormatRemoved;
sigc::signal<FormatPtr, FormatPtr> NewFormat;
/* Compatibility with other elements */
sigc::signal<void> 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<FormatPtr> format;
Gtk::TreeModelColumn<Glib::ustring> label;
FormatCols () { add (format); add (label); }
};
FormatCols format_cols;
Glib::RefPtr<Gtk::ListStore> format_list;
Gtk::ComboBox format_combo;
Gtk::Button edit_button;
Gtk::Button remove_button;
Gtk::Button new_button;
};
#endif /* __export_format_selector_h__ */

View File

@ -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 <sigc++/signal.h>
#include <pbd/filesystem.h>
#include "utils.h"
#include <ardour/export_handler.h>
#include <ardour/export_filename.h>
#include <ardour/export_format_specification.h>
#include <ardour/export_channel_configuration.h>
#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 (_("<span color=\"#ffa755\">Some already existing files will be overwritten.</span>"), 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<ExportProfileManager::Warnings> warnings = profile_manager->get_warnings();
for (std::list<Glib::ustring>::iterator it = warnings->errors.begin(); it != warnings->errors.end(); ++it) {
add_error (*it);
}
for (std::list<Glib::ustring>::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<Glib::ustring>::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) + "<b>" + it->substr (pos + 1) + "</b>";
}
}
}
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<FilePage *> (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<FilePage *> (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<FilePage *> (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 = _("<span color=\"#ffa755\">Error: ") + text + "</span>";
} else {
warn_string = _("<span color=\"#ffa755\">Error: ") + text + "</span>\n" + warn_string;
}
warn_label.set_markup (warn_string);
}
void
ExportMainDialog::add_warning (Glib::ustring const & text)
{
if (warn_string.empty()) {
warn_string = _("<span color=\"#ffa755\">Warning: ") + text + "</span>";
} else {
warn_string = warn_string + _("\n<span color=\"#ffa755\">Warning: ") + text + "</span>";
}
warn_label.set_markup (warn_string);
}

View File

@ -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 <ardour/export_handler.h>
#include <ardour/export_profile_manager.h>
#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 <gtkmm.h>
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<ARDOUR::ExportTimespan> TimespanPtr;
typedef boost::shared_ptr<std::list<TimespanPtr> > TimespanList;
typedef boost::shared_ptr<ARDOUR::ExportChannelConfiguration> ChannelConfigPtr;
typedef std::list<ChannelConfigPtr> ChannelConfigList;
typedef boost::shared_ptr<ARDOUR::ExportFilename> FilenamePtr;
typedef boost::shared_ptr<ARDOUR::ExportHandler> HandlerPtr;
typedef boost::shared_ptr<ARDOUR::ExportFormatSpecification> FormatPtr;
typedef boost::shared_ptr<ARDOUR::ExportProfileManager> 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<PresetPtr> preset;
Gtk::TreeModelColumn<Glib::ustring> label;
PresetCols () { add (preset); add (label); }
};
PresetCols preset_cols;
Glib::RefPtr<Gtk::ListStore> 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<void> 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__ */

View File

@ -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 <cassert>
#include <pbd/compose.h>
#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<ARDOUR::ExportProfileManager> _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<ExportProfileManager::TimespanNodePtr>::const_iterator it = graph->timespans.begin(); it != graph->timespans.end(); ++it) {
draw_timespan (*it, get_bounds (it->get(), Timespans, max_level));
}
for (list<ExportProfileManager::ChannelConfigNodePtr>::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<ExportProfileManager::FormatNodePtr>::const_iterator it = graph->formats.begin(); it != graph->formats.end(); ++it) {
draw_format (*it, get_bounds (it->get(), Formats, max_level));
}
for (list<ExportProfileManager::FilenameNodePtr>::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<uint32_t, uint32_t>
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<ExportProfileManager::TimespanNodePtr>::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<ExportProfileManager::ChannelConfigNodePtr>::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<ExportProfileManager::FormatNodePtr>::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<ExportProfileManager::FilenameNodePtr>::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<uint32_t, uint32_t> (left_bound, right_bound);
}
void
ExportMultiplicator::draw_timespan (ARDOUR::ExportProfileManager::TimespanNodePtr node, std::pair<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<Gtk::HBox>
ExportMultiplicator::get_hbox (TablePosition position)
{
WidgetMap::iterator it = widget_map.find (position);
if (it != widget_map.end()) { return it->second; }
boost::shared_ptr<Gtk::HBox> widget = widget_map.insert (WidgetPair (position, boost::shared_ptr<Gtk::HBox> (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<ExportProfileManager> 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>"
" <popup name='PopupMenu'>"
" <menuitem action='Split'/>"
" <menuitem action='Remove'/>"
" </popup>"
"</ui>";
ui_manager->add_ui_from_string (ui_info);
menu = dynamic_cast<Gtk::Menu*> (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);
}

View File

@ -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 <utility>
#include <map>
#include <ardour/export_profile_manager.h>
#include <gtkmm.h>
#include <boost/shared_ptr.hpp>
using std::list;
using ARDOUR::ExportProfileManager;
class ExportMultiplicator : public Gtk::EventBox {
public:
ExportMultiplicator ();
~ExportMultiplicator ();
void set_manager (boost::shared_ptr<ExportProfileManager> _manager);
private:
boost::shared_ptr<ExportProfileManager> 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<uint32_t, uint32_t> get_bounds (ExportProfileManager::GraphNode * node, GraphLevel current_level, GraphLevel max_level) const;
void draw_timespan (ExportProfileManager::TimespanNodePtr node, std::pair<uint32_t, uint32_t> bounds);
void draw_channel_config (ExportProfileManager::ChannelConfigNodePtr node, std::pair<uint32_t, uint32_t> bounds);
void draw_format (ExportProfileManager::FormatNodePtr node, std::pair<uint32_t, uint32_t> bounds);
void draw_filename (ExportProfileManager::FilenameNodePtr node, std::pair<uint32_t, uint32_t> 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<TablePosition, boost::shared_ptr<Gtk::HBox> > WidgetMap;
typedef std::pair<TablePosition, boost::shared_ptr<Gtk::HBox> > WidgetPair;
boost::shared_ptr<Gtk::HBox> get_hbox (TablePosition position);
WidgetMap widget_map;
/* Button Widget */
class ButtonWidget : public Gtk::EventBox {
public:
ButtonWidget (Glib::ustring name, boost::shared_ptr<ExportProfileManager> 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<ExportProfileManager> manager;
ExportProfileManager::GraphNode * node;
float split_position;
/* Context menu */
Glib::RefPtr<Gtk::ActionGroup> menu_actions;
Glib::RefPtr<Gtk::UIManager> ui_manager;
Gtk::Menu * menu;
};
};
#endif /* __export_multiplicator_h__ */

View File

@ -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 <ardour/location.h>
#include <ardour/types.h>
#include <ardour/session.h>
#include <ardour/export_handler.h>
#include <ardour/export_timespan.h>
#include <pbd/enumwriter.h>
#include <pbd/convert.h>
#include <sstream>
#include <iomanip>
#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<Gtk::CellRendererToggle *> (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<Gtk::CellRendererText *> (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 += "<span color=\"#7fff7f\">";
label += start;
// label += "</span>";
label += _(" to ");
// label += "<span color=\"#7fff7f\">";
label += end;
// label += "</span>";
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();
}

View File

@ -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 <list>
#include <gtkmm.h>
#include <boost/shared_ptr.hpp>
#include <ardour/types.h>
#include <ardour/export_profile_manager.h>
namespace ARDOUR {
class Location;
class ExportTimespan;
class ExportHandler;
class Session;
}
using ARDOUR::CDMarkerFormat;
///
class ExportTimespanSelector : public Gtk::VBox {
private:
typedef std::list<ARDOUR::Location *> LocationList;
typedef boost::shared_ptr<ARDOUR::ExportHandler> HandlerPtr;
typedef boost::shared_ptr<ARDOUR::ExportTimespan> TimespanPtr;
typedef std::list<TimespanPtr> TimespanList;
typedef boost::shared_ptr<TimespanList> 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<void> 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<TimeFormat> format;
Gtk::TreeModelColumn<Glib::ustring> label;
TimeFormatCols () { add(format); add(label); }
};
TimeFormatCols time_format_cols;
Glib::RefPtr<Gtk::ListStore> time_format_list;
Gtk::ComboBox time_format_combo;
/* View */
struct RangeCols : public Gtk::TreeModelColumnRecord
{
public:
Gtk::TreeModelColumn<ARDOUR::Location *> location;
Gtk::TreeModelColumn<Glib::ustring> label;
Gtk::TreeModelColumn<bool> selected;
Gtk::TreeModelColumn<Glib::ustring> name;
RangeCols () { add (location); add(label); add(selected); add(name); }
};
RangeCols range_cols;
Glib::RefPtr<Gtk::ListStore> range_list;
Gtk::TreeView range_view;
Gtk::ScrolledWindow range_scroller;
};
#endif /* __export_timespan_selector_h__ */

View File

@ -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 <sstream>
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/window_title.h>
#include "i18n.h"
#include <pbd/xml++.h>
#include <ardour/session.h>
#include <ardour/session_directory.h>
#include <ardour/session_utils.h>
#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 = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
+ "<span weight=\"bold\">" + import_field->value() + "</span>";
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 <typename DataSet>
SessionMetadataDialog<DataSet>::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 <typename DataSet>
void
SessionMetadataDialog<DataSet>::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 <typename DataSet>
void
SessionMetadataDialog<DataSet>::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 <typename DataSet>
void
SessionMetadataDialog<DataSet>::save_data ()
{
for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
(*it)->save_data ();
}
}
template <typename DataSet>
void
SessionMetadataDialog<DataSet>::save_and_close ()
{
save_data ();
end_dialog ();
}
template <typename DataSet>
void
SessionMetadataDialog<DataSet>::end_dialog ()
{
hide_all();
}
template <typename DataSet>
void
SessionMetadataDialog<DataSet>::warn_user (ustring const & string)
{
Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
msg.run();
}
template <typename DataSet>
boost::shared_ptr<std::list<Gtk::Widget *> >
SessionMetadataDialog<DataSet>::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<DataSet *> (it->get());
list->push_back (& CALL_MEMBER_FN (*set, f) ());
}
return list;
}
template <typename DataSet>
void
SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
{
get_vbox()->pack_start (widget, true, true, 0);
}
template <typename DataSet>
void
SessionMetadataDialog<DataSet>::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 <typename DataSet>
void
SessionMetadataDialog<DataSet>::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 <typename DataSet>
void
SessionMetadataDialog<DataSet>::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<SessionMetadataSetEditable> (_("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<SessionMetadataSetImportable> (_("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();
}

View File

@ -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 <gtkmm.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <list>
#include <ardour/session_metadata.h>
using std::string;
using Glib::ustring;
class MetadataField;
typedef boost::shared_ptr<MetadataField> 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<MetadataPtr> 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<ustring> field;
Gtk::TreeModelColumn<ustring> values;
Gtk::TreeModelColumn<bool> import;
Gtk::TreeModelColumn<MetadataPtr> data;
Columns() { add (field); add (values); add (import); add (data); }
};
Glib::RefPtr<Gtk::ListStore> 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 <typename DataSet>
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<Gtk::Widget *> WidgetList;
typedef boost::shared_ptr<WidgetList> 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<SessionMetadataSet> DataSetPtr;
typedef std::list<DataSetPtr> DataSetList;
DataSetList data_list;
Gtk::Button * save_button;
Gtk::Button * cancel_button;
};
class SessionMetadataEditor : public SessionMetadataDialog<SessionMetadataSetEditable> {
public:
SessionMetadataEditor ();
~SessionMetadataEditor ();
void run ();
private:
void init_gui ();
};
class SessionMetadataImporter : public SessionMetadataDialog<SessionMetadataSetImportable> {
public:
SessionMetadataImporter ();
~SessionMetadataImporter ();
void run ();
private:
void init_gui ();
// Select all from -widget
Gtk::HBox selection_hbox;
Gtk::Label selection_label;
};
#endif

View File

@ -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;
}