2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "export_timespan_selector.h"
23 #include "ardour/location.h"
24 #include "ardour/types.h"
25 #include "ardour/session.h"
26 #include "ardour/export_handler.h"
27 #include "ardour/export_timespan.h"
29 #include "pbd/enumwriter.h"
30 #include "pbd/string_convert.h"
38 using namespace ARDOUR;
42 ExportTimespanSelector::ExportTimespanSelector (ARDOUR::Session * session, ProfileManagerPtr manager, bool multi)
44 , _realtime_available (true)
45 , time_format_label (_("Show Times as:"), Gtk::ALIGN_LEFT)
46 , realtime_checkbutton (_("Realtime Export"))
48 set_session (session);
50 option_hbox.pack_start (time_format_label, false, false, 0);
51 option_hbox.pack_start (time_format_combo, false, false, 6);
54 Gtk::Button* b = Gtk::manage (new Gtk::Button (_("Select All")));
55 b->signal_clicked().connect (
57 sigc::mem_fun (*this, &ExportTimespanSelector::set_selection_state_of_all_timespans), true
60 option_hbox.pack_start (*b, false, false, 6);
62 b = Gtk::manage (new Gtk::Button (_("Deselect All")));
63 b->signal_clicked().connect (
65 sigc::mem_fun (*this, &ExportTimespanSelector::set_selection_state_of_all_timespans), false
68 option_hbox.pack_start (*b, false, false, 6);
70 option_hbox.pack_start (realtime_checkbutton, false, false, 6);
71 realtime_checkbutton.set_active (session->config.get_realtime_export ());
73 realtime_checkbutton.signal_toggled ().connect (
74 sigc::mem_fun (*this, &ExportTimespanSelector::toggle_realtime)
77 range_scroller.add (range_view);
79 pack_start (option_hbox, false, false, 0);
80 pack_start (range_scroller, true, true, 6);
84 Gtk::TreeModel::iterator iter;
85 Gtk::TreeModel::Row row;
87 /* Time format combo */
89 time_format_list = Gtk::ListStore::create (time_format_cols);
90 time_format_combo.set_model (time_format_list);
92 iter = time_format_list->append();
94 row[time_format_cols.format] = ExportProfileManager::Timecode;
95 row[time_format_cols.label] = _("Timecode");
97 iter = time_format_list->append();
99 row[time_format_cols.format] = ExportProfileManager::MinSec;
100 row[time_format_cols.label] = _("Minutes:Seconds");
102 iter = time_format_list->append();
104 row[time_format_cols.format] = ExportProfileManager::BBT;
105 row[time_format_cols.label] = _("Bars:Beats");
107 time_format_combo.pack_start (time_format_cols.label);
108 time_format_combo.set_active (0);
110 time_format_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportTimespanSelector::change_time_format));
114 range_list = Gtk::ListStore::create (range_cols);
115 // order by location start times
116 range_list->set_sort_column(range_cols.location, Gtk::SORT_ASCENDING);
117 range_list->set_sort_func(range_cols.location, sigc::mem_fun(*this, &ExportTimespanSelector::location_sorter));
118 range_view.set_model (range_list);
119 range_view.set_headers_visible (true);
122 ExportTimespanSelector::~ExportTimespanSelector ()
128 ExportTimespanSelector::location_sorter(Gtk::TreeModel::iterator a, Gtk::TreeModel::iterator b)
130 Location *l1 = (*a)[range_cols.location];
131 Location *l2 = (*b)[range_cols.location];
132 const Location *ls = _session->locations()->session_range_location();
134 // always sort session range first
140 return l1->start() - l2->start();
144 ExportTimespanSelector::add_range_to_selection (ARDOUR::Location const * loc, bool rt)
146 ExportTimespanPtr span = _session->get_export_handler()->add_timespan();
149 if (loc == state->selection_range.get()) {
152 id = loc->id().to_s();
155 span->set_range (loc->start(), loc->end());
156 span->set_name (loc->name());
157 span->set_range_id (id);
158 span->set_realtime (rt);
159 state->timespans->push_back (span);
163 ExportTimespanSelector::set_time_format_from_state ()
165 Gtk::TreeModel::Children::iterator tree_it;
166 for (tree_it = time_format_list->children().begin(); tree_it != time_format_list->children().end(); ++tree_it) {
167 if (tree_it->get_value (time_format_cols.format) == state->time_format) {
168 time_format_combo.set_active (tree_it);
174 ExportTimespanSelector::sync_with_manager ()
176 state = manager->get_timespans().front();
178 CriticalSelectionChanged();
182 ExportTimespanSelector::allow_realtime_export (bool yn)
184 if (_realtime_available == yn) {
187 _realtime_available = yn;
188 realtime_checkbutton.set_sensitive (_realtime_available);
193 ExportTimespanSelector::toggle_realtime ()
195 const bool realtime = !_session->config.get_realtime_export ();
196 _session->config.set_realtime_export (realtime);
197 realtime_checkbutton.set_inconsistent (false);
198 realtime_checkbutton.set_active (realtime);
200 for (Gtk::TreeStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) {
201 it->set_value (range_cols.realtime, realtime);
206 ExportTimespanSelector::change_time_format ()
208 state->time_format = time_format_combo.get_active()->get_value (time_format_cols.format);
210 for (Gtk::ListStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) {
211 Location * location = it->get_value (range_cols.location);
212 it->set_value (range_cols.label, construct_label (location));
213 it->set_value (range_cols.length, construct_length (location));
218 ExportTimespanSelector::construct_label (ARDOUR::Location const * location) const
224 framepos_t start_frame = location->start();
225 framepos_t end_frame = location->end();
227 switch (state->time_format) {
228 case AudioClock::BBT:
229 start = bbt_str (start_frame);
230 end = bbt_str (end_frame);
233 case AudioClock::Timecode:
234 start = timecode_str (start_frame);
235 end = timecode_str (end_frame);
238 case AudioClock::MinSec:
239 start = ms_str (start_frame);
240 end = ms_str (end_frame);
243 case AudioClock::Frames:
244 start = to_string (start_frame);
245 end = to_string (end_frame);
249 // label += _("from ");
251 // label += "<span color=\"#7fff7f\">";
253 // label += "</span>";
257 // label += "<span color=\"#7fff7f\">";
259 // label += "</span>";
265 ExportTimespanSelector::construct_length (ARDOUR::Location const * location) const
267 if (location->length() == 0) {
273 switch (state->time_format) {
274 case AudioClock::BBT:
275 s << bbt_str (location->length ());
278 case AudioClock::Timecode:
281 _session->timecode_duration (location->length(), tc);
286 case AudioClock::MinSec:
287 s << ms_str (location->length ());
290 case AudioClock::Frames:
291 s << location->length ();
300 ExportTimespanSelector::bbt_str (framepos_t frames) const
306 std::ostringstream oss;
307 Timecode::BBT_Time time;
308 _session->bbt_time (frames, time);
310 print_padded (oss, time);
315 ExportTimespanSelector::timecode_str (framecnt_t frames) const
321 std::ostringstream oss;
324 _session->timecode_time (frames, time);
326 oss << std::setfill('0') << std::right <<
330 time.minutes << ":" <<
332 time.seconds << ":" <<
340 ExportTimespanSelector::ms_str (framecnt_t frames) const
346 std::ostringstream oss;
354 hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
355 left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
356 mins = (int) floor (left / (_session->frame_rate() * 60.0f));
357 left -= (framecnt_t) floor (mins * _session->frame_rate() * 60.0f);
358 secs = (int) floor (left / (float) _session->frame_rate());
359 left -= (framecnt_t) floor ((double)(secs * _session->frame_rate()));
360 sec_promilles = (int) (left * 1000 / (float) _session->frame_rate() + 0.5);
362 oss << std::setfill('0') << std::right <<
376 ExportTimespanSelector::update_range_name (std::string const & path, std::string const & new_text)
378 Gtk::TreeStore::iterator it = range_list->get_iter (path);
379 it->get_value (range_cols.location)->set_name (new_text);
381 CriticalSelectionChanged();
385 ExportTimespanSelector::set_selection_state_of_all_timespans (bool s)
387 for (Gtk::ListStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) {
388 it->set_value (range_cols.selected, s);
392 /*** ExportTimespanSelectorSingle ***/
394 ExportTimespanSelectorSingle::ExportTimespanSelectorSingle (ARDOUR::Session * session, ProfileManagerPtr manager, std::string range_id) :
395 ExportTimespanSelector (session, manager, false),
398 range_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
399 range_view.append_column_editable (_("RT"), range_cols.realtime);
400 range_view.append_column_editable (_("Range"), range_cols.name);
402 if (Gtk::CellRendererToggle * renderer = dynamic_cast<Gtk::CellRendererToggle *> (range_view.get_column_cell_renderer (0))) {
403 renderer->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &ExportTimespanSelectorSingle::update_timespans)));
406 if (Gtk::CellRendererText * renderer = dynamic_cast<Gtk::CellRendererText *> (range_view.get_column_cell_renderer (1))) {
407 renderer->signal_edited().connect (sigc::mem_fun (*this, &ExportTimespanSelectorSingle::update_range_name));
410 Gtk::CellRendererText * label_render = Gtk::manage (new Gtk::CellRendererText());
411 Gtk::TreeView::Column * label_col = Gtk::manage (new Gtk::TreeView::Column (_("Time Span"), *label_render));
412 label_col->add_attribute (label_render->property_markup(), range_cols.label);
413 range_view.append_column (*label_col);
415 range_view.append_column (_("Length"), range_cols.length);
419 ExportTimespanSelectorSingle::allow_realtime_export (bool yn)
421 ExportTimespanSelector::allow_realtime_export (yn);
422 range_view.get_column (0)->set_visible (_realtime_available);
426 ExportTimespanSelectorSingle::fill_range_list ()
428 if (!state) { return; }
429 const bool realtime = _session->config.get_realtime_export ();
432 if (!range_id.compare (X_("selection"))) {
433 id = state->selection_range->id().to_s();
439 state->timespans->clear();
441 Gtk::TreeModel::iterator iter;
442 Gtk::TreeModel::Row row;
443 for (LocationList::const_iterator it = state->ranges->begin(); it != state->ranges->end(); ++it) {
445 if (!(*it)->id().to_s().compare (id)) {
446 iter = range_list->append();
449 row[range_cols.location] = *it;
450 row[range_cols.selected] = true;
451 row[range_cols.realtime] = realtime;
452 row[range_cols.name] = (*it)->name();
453 row[range_cols.label] = construct_label (*it);
454 row[range_cols.length] = construct_length (*it);
456 add_range_to_selection (*it, false);
462 set_time_format_from_state();
466 ExportTimespanSelectorSingle::update_timespans ()
468 state->timespans->clear();
469 const bool realtime = _session->config.get_realtime_export ();
470 bool inconsistent = false;
472 for (Gtk::TreeStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) {
473 add_range_to_selection (it->get_value (range_cols.location), it->get_value (range_cols.realtime) && _realtime_available);
474 if (it->get_value (range_cols.realtime) != realtime) {
478 realtime_checkbutton.set_inconsistent (inconsistent);
481 /*** ExportTimespanSelectorMultiple ***/
483 ExportTimespanSelectorMultiple::ExportTimespanSelectorMultiple (ARDOUR::Session * session, ProfileManagerPtr manager) :
484 ExportTimespanSelector (session, manager, true)
486 range_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
487 range_view.append_column_editable ("", range_cols.selected);
488 range_view.append_column_editable (_("RT"), range_cols.realtime);
489 range_view.append_column_editable (_("Range"), range_cols.name);
491 if (Gtk::CellRendererToggle * renderer = dynamic_cast<Gtk::CellRendererToggle *> (range_view.get_column_cell_renderer (0))) {
492 renderer->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &ExportTimespanSelectorMultiple::update_selection)));
494 if (Gtk::CellRendererToggle * renderer = dynamic_cast<Gtk::CellRendererToggle *> (range_view.get_column_cell_renderer (1))) {
495 renderer->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &ExportTimespanSelectorMultiple::update_selection)));
497 if (Gtk::CellRendererText * renderer = dynamic_cast<Gtk::CellRendererText *> (range_view.get_column_cell_renderer (2))) {
498 renderer->signal_edited().connect (sigc::mem_fun (*this, &ExportTimespanSelectorMultiple::update_range_name));
501 Gtk::CellRendererText * label_render = Gtk::manage (new Gtk::CellRendererText());
502 Gtk::TreeView::Column * label_col = Gtk::manage (new Gtk::TreeView::Column (_("Time Span"), *label_render));
503 label_col->add_attribute (label_render->property_markup(), range_cols.label);
504 range_view.append_column (*label_col);
506 range_view.append_column (_("Length"), range_cols.length);
510 ExportTimespanSelectorMultiple::allow_realtime_export (bool yn)
512 ExportTimespanSelector::allow_realtime_export (yn);
513 range_view.get_column (1)->set_visible (_realtime_available);
517 ExportTimespanSelectorMultiple::fill_range_list ()
519 if (!state) { return; }
520 const bool realtime = _session->config.get_realtime_export ();
524 Gtk::TreeModel::iterator iter;
525 Gtk::TreeModel::Row row;
526 for (LocationList::const_iterator it = state->ranges->begin(); it != state->ranges->end(); ++it) {
528 iter = range_list->append();
531 row[range_cols.location] = *it;
532 row[range_cols.selected] = false;
533 row[range_cols.realtime] = realtime;
534 row[range_cols.name] = (*it)->name();
535 row[range_cols.label] = construct_label (*it);
536 row[range_cols.length] = construct_length (*it);
539 set_selection_from_state ();
543 ExportTimespanSelectorMultiple::set_selection_from_state ()
545 Gtk::TreeModel::Children::iterator tree_it;
547 for (TimespanList::iterator it = state->timespans->begin(); it != state->timespans->end(); ++it) {
548 string id = (*it)->range_id();
549 for (tree_it = range_list->children().begin(); tree_it != range_list->children().end(); ++tree_it) {
550 Location * loc = tree_it->get_value (range_cols.location);
552 if ((id == "selection" && loc == state->selection_range.get()) ||
553 (id == loc->id().to_s())) {
554 tree_it->set_value (range_cols.selected, true);
555 tree_it->set_value (range_cols.realtime, (*it)->realtime ());
560 set_time_format_from_state();
564 ExportTimespanSelectorMultiple::update_selection ()
567 CriticalSelectionChanged ();
571 ExportTimespanSelectorMultiple::update_timespans ()
573 state->timespans->clear();
574 const bool realtime = _session->config.get_realtime_export ();
575 bool inconsistent = false;
577 for (Gtk::TreeStore::Children::iterator it = range_list->children().begin(); it != range_list->children().end(); ++it) {
578 if (it->get_value (range_cols.selected)) {
579 add_range_to_selection (it->get_value (range_cols.location), it->get_value (range_cols.realtime) && _realtime_available);
581 if (it->get_value (range_cols.realtime) != realtime) {
585 realtime_checkbutton.set_inconsistent (inconsistent);