2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <sigc++/bind.h>
30 #include <pbd/convert.h>
31 #include <pbd/error.h>
32 #include <pbd/enumwriter.h>
33 #include <pbd/memento_command.h>
35 #include <glibmm/miscutils.h>
36 #include <gtkmm/image.h>
37 #include <gdkmm/color.h>
38 #include <gdkmm/bitmap.h>
40 #include <gtkmm2ext/grouped_buttons.h>
41 #include <gtkmm2ext/gtk_ui.h>
42 #include <gtkmm2ext/tearoff.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/window_title.h>
45 #include <gtkmm2ext/choice.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audio_diskstream.h>
49 #include <ardour/plugin_manager.h>
50 #include <ardour/location.h>
51 #include <ardour/audioplaylist.h>
52 #include <ardour/audioregion.h>
53 #include <ardour/region.h>
54 #include <ardour/session_route.h>
55 #include <ardour/tempo.h>
56 #include <ardour/utils.h>
58 #include <control_protocol/control_protocol.h>
60 #include "ardour_ui.h"
64 #include "playlist_selector.h"
65 #include "audio_region_view.h"
66 #include "rgb_macros.h"
67 #include "selection.h"
68 #include "audio_streamview.h"
69 #include "time_axis_view.h"
70 #include "audio_time_axis.h"
72 #include "crossfade_view.h"
74 #include "public_editor.h"
75 #include "crossfade_edit.h"
76 #include "canvas_impl.h"
78 #include "gui_thread.h"
81 #include "analysis_window.h"
87 #include "imageframe_socket_handler.h"
92 using namespace ARDOUR;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
99 using PBD::internationalize;
102 const double Editor::timebar_height = 15.0;
104 #include "editor_xpms"
106 static const gchar *_snap_type_strings[] = {
130 static const gchar *_snap_mode_strings[] = {
136 static const gchar *_zoom_focus_strings[] = {
145 /* Soundfile drag-n-drop */
147 Gdk::Cursor* Editor::cross_hair_cursor = 0;
148 Gdk::Cursor* Editor::selector_cursor = 0;
149 Gdk::Cursor* Editor::trimmer_cursor = 0;
150 Gdk::Cursor* Editor::grabber_cursor = 0;
151 Gdk::Cursor* Editor::zoom_cursor = 0;
152 Gdk::Cursor* Editor::time_fx_cursor = 0;
153 Gdk::Cursor* Editor::fader_cursor = 0;
154 Gdk::Cursor* Editor::speaker_cursor = 0;
155 Gdk::Cursor* Editor::wait_cursor = 0;
156 Gdk::Cursor* Editor::timebar_cursor = 0;
159 show_me_the_size (Requisition* r, const char* what)
161 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
165 check_adjustment (Gtk::Adjustment* adj)
167 cerr << "CHANGE adj = "
168 << adj->get_lower () << ' '
169 << adj->get_upper () << ' '
170 << adj->get_value () << ' '
171 << adj->get_step_increment () << ' '
172 << adj->get_page_increment () << ' '
173 << adj->get_page_size () << ' '
180 /* time display buttons */
182 minsec_label (_("Mins:Secs")),
183 bbt_label (_("Bars:Beats")),
184 smpte_label (_("Timecode")),
185 frame_label (_("Frames")),
186 tempo_label (_("Tempo")),
187 meter_label (_("Meter")),
188 mark_label (_("Location Markers")),
189 range_mark_label (_("Range Markers")),
190 transport_mark_label (_("Loop/Punch Ranges")),
192 edit_packer (3, 3, false),
194 /* the values here don't matter: layout widgets
195 reset them as needed.
198 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
199 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
201 /* tool bar related */
203 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
204 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
206 toolbar_selection_clock_table (2,3),
208 automation_mode_button (_("mode")),
209 global_automation_button (_("automation")),
212 image_socket_listener(0),
217 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
222 /* we are a singleton */
224 PublicEditor::_instance = this;
228 selection = new Selection;
229 cut_buffer = new Selection;
231 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
232 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
233 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
234 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
236 clicked_regionview = 0;
237 clicked_axisview = 0;
238 clicked_routeview = 0;
239 clicked_crossfadeview = 0;
240 clicked_control_point = 0;
241 latest_regionview = 0;
242 last_update_frame = 0;
244 current_mixer_strip = 0;
245 current_bbt_points = 0;
247 snap_type_strings = I18N (_snap_type_strings);
248 snap_mode_strings = I18N (_snap_mode_strings);
249 zoom_focus_strings = I18N(_zoom_focus_strings);
251 snap_type = SnapToFrame;
252 set_snap_to (snap_type);
253 snap_mode = SnapNormal;
254 set_snap_mode (snap_mode);
255 snap_threshold = 5.0;
256 bbt_beat_subdivision = 4;
259 autoscroll_active = false;
260 autoscroll_timeout_tag = -1;
261 interthread_progress_window = 0;
267 current_interthread_info = 0;
268 _show_measures = true;
269 _show_waveforms = true;
270 _show_waveforms_recording = true;
271 first_action_message = 0;
273 show_gain_after_trim = false;
274 ignore_route_list_reorder = false;
275 no_route_list_redisplay = false;
276 verbose_cursor_on = true;
277 route_removal = false;
278 show_automatic_regions_in_region_list = true;
279 region_list_sort_type = (Editing::RegionListSortType) 0;
280 have_pending_keyboard_selection = false;
281 _follow_playhead = true;
282 _xfade_visibility = true;
283 editor_ruler_menu = 0;
284 no_ruler_shown_update = false;
285 edit_group_list_menu = 0;
287 region_list_menu = 0;
289 start_end_marker_menu = 0;
290 range_marker_menu = 0;
291 marker_menu_item = 0;
293 transport_marker_menu = 0;
294 new_transport_marker_menu = 0;
295 editor_mixer_strip_width = Wide;
296 show_editor_mixer_when_tracks_arrive = false;
299 ignore_mouse_mode_toggle = false;
300 current_stepping_trackview = 0;
302 entered_regionview = 0;
303 clear_entered_track = false;
304 _new_regionviews_show_envelope = false;
305 current_timestretch = 0;
306 in_edit_group_row_change = false;
307 last_canvas_frame = 0;
310 button_release_can_deselect = true;
311 canvas_idle_queued = false;
312 _dragging_playhead = false;
313 _dragging_hscrollbar = false;
315 location_marker_color = color_map[cLocationMarker];
316 location_range_color = color_map[cLocationRange];
317 location_cd_marker_color = color_map[cLocationCDMarker];
318 location_loop_color = color_map[cLocationLoop];
319 location_punch_color = color_map[cLocationPunch];
321 range_marker_drag_rect = 0;
322 marker_drag_line = 0;
324 set_mouse_mode (MouseObject, true);
326 frames_per_unit = 2048; /* too early to use reset_zoom () */
327 reset_hscrollbar_stepping ();
329 zoom_focus = ZoomFocusLeft;
330 set_zoom_focus (ZoomFocusLeft);
331 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
333 initialize_rulers ();
334 initialize_canvas ();
336 edit_controls_vbox.set_spacing (0);
337 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
338 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
340 track_canvas.set_hadjustment (horizontal_adjustment);
341 track_canvas.set_vadjustment (vertical_adjustment);
342 time_canvas.set_hadjustment (horizontal_adjustment);
344 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
345 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
347 controls_layout.add (edit_controls_vbox);
348 controls_layout.set_name ("EditControlsBase");
349 controls_layout.add_events (Gdk::SCROLL_MASK);
350 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
352 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
353 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
354 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
356 edit_vscrollbar.set_adjustment (vertical_adjustment);
357 edit_hscrollbar.set_adjustment (horizontal_adjustment);
359 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
360 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
361 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
363 edit_hscrollbar.set_name ("EditorHScrollbar");
368 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
370 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
371 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
372 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
373 time_canvas_vbox.pack_start (*frames_ruler, false, false);
374 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
375 time_canvas_vbox.pack_start (time_canvas, true, true);
376 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
378 bbt_label.set_name ("EditorTimeButton");
379 bbt_label.set_size_request (-1, (int)timebar_height);
380 bbt_label.set_alignment (1.0, 0.5);
381 bbt_label.set_padding (5,0);
382 minsec_label.set_name ("EditorTimeButton");
383 minsec_label.set_size_request (-1, (int)timebar_height);
384 minsec_label.set_alignment (1.0, 0.5);
385 minsec_label.set_padding (5,0);
386 smpte_label.set_name ("EditorTimeButton");
387 smpte_label.set_size_request (-1, (int)timebar_height);
388 smpte_label.set_alignment (1.0, 0.5);
389 smpte_label.set_padding (5,0);
390 frame_label.set_name ("EditorTimeButton");
391 frame_label.set_size_request (-1, (int)timebar_height);
392 frame_label.set_alignment (1.0, 0.5);
393 frame_label.set_padding (5,0);
394 tempo_label.set_name ("EditorTimeButton");
395 tempo_label.set_size_request (-1, (int)timebar_height);
396 tempo_label.set_alignment (1.0, 0.5);
397 tempo_label.set_padding (5,0);
398 meter_label.set_name ("EditorTimeButton");
399 meter_label.set_size_request (-1, (int)timebar_height);
400 meter_label.set_alignment (1.0, 0.5);
401 meter_label.set_padding (5,0);
402 mark_label.set_name ("EditorTimeButton");
403 mark_label.set_size_request (-1, (int)timebar_height);
404 mark_label.set_alignment (1.0, 0.5);
405 mark_label.set_padding (5,0);
406 range_mark_label.set_name ("EditorTimeButton");
407 range_mark_label.set_size_request (-1, (int)timebar_height);
408 range_mark_label.set_alignment (1.0, 0.5);
409 range_mark_label.set_padding (5,0);
410 transport_mark_label.set_name ("EditorTimeButton");
411 transport_mark_label.set_size_request (-1, (int)timebar_height);
412 transport_mark_label.set_alignment (1.0, 0.5);
413 transport_mark_label.set_padding (5,0);
415 time_button_vbox.pack_start (minsec_label, false, false);
416 time_button_vbox.pack_start (smpte_label, false, false);
417 time_button_vbox.pack_start (frame_label, false, false);
418 time_button_vbox.pack_start (bbt_label, false, false);
419 time_button_vbox.pack_start (meter_label, false, false);
420 time_button_vbox.pack_start (tempo_label, false, false);
421 time_button_vbox.pack_start (mark_label, false, false);
423 time_button_event_box.add (time_button_vbox);
425 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
426 time_button_event_box.set_name ("TimebarLabelBase");
427 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
429 time_button_frame.add(time_button_event_box);
430 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
432 /* these enable us to have a dedicated window (for cursor setting, etc.)
433 for the canvas areas.
436 track_canvas_event_box.add (track_canvas);
438 time_canvas_event_box.add (time_canvas_vbox);
439 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
441 edit_packer.set_col_spacings (0);
442 edit_packer.set_row_spacings (0);
443 edit_packer.set_homogeneous (false);
444 edit_packer.set_border_width (0);
445 edit_packer.set_name ("EditorWindow");
447 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
449 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
450 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
452 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
453 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
455 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
456 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
458 bottom_hbox.set_border_width (2);
459 bottom_hbox.set_spacing (3);
461 route_display_model = ListStore::create(route_display_columns);
462 route_list_display.set_model (route_display_model);
463 route_list_display.append_column (_("Show"), route_display_columns.visible);
464 route_list_display.append_column (_("Name"), route_display_columns.text);
465 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
466 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
467 route_list_display.set_headers_visible (true);
468 route_list_display.set_name ("TrackListDisplay");
469 route_list_display.get_selection()->set_mode (SELECTION_NONE);
470 route_list_display.set_reorderable (true);
471 route_list_display.set_size_request (100,-1);
473 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
474 route_list_visible_cell->property_activatable() = true;
475 route_list_visible_cell->property_radio() = false;
477 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
478 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
480 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
482 route_list_scroller.add (route_list_display);
483 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
485 group_model = ListStore::create(group_columns);
486 edit_group_display.set_model (group_model);
487 edit_group_display.append_column (_("Name"), group_columns.text);
488 edit_group_display.append_column (_("Active"), group_columns.is_active);
489 edit_group_display.append_column (_("Show"), group_columns.is_visible);
490 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
491 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
492 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
493 edit_group_display.get_column (0)->set_expand (true);
494 edit_group_display.get_column (1)->set_expand (false);
495 edit_group_display.get_column (2)->set_expand (false);
496 edit_group_display.set_headers_visible (true);
498 /* name is directly editable */
500 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
501 name_cell->property_editable() = true;
502 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
504 /* use checkbox for the active + visible columns */
506 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
507 active_cell->property_activatable() = true;
508 active_cell->property_radio() = false;
510 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
511 active_cell->property_activatable() = true;
512 active_cell->property_radio() = false;
514 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
516 edit_group_display.set_name ("EditGroupList");
517 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
518 edit_group_display.set_headers_visible (true);
519 edit_group_display.set_reorderable (false);
520 edit_group_display.set_rules_hint (true);
521 edit_group_display.set_size_request (75, -1);
523 edit_group_display_scroller.add (edit_group_display);
524 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
526 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
528 VBox* edit_group_display_packer = manage (new VBox());
529 HBox* edit_group_display_button_box = manage (new HBox());
530 edit_group_display_button_box->set_homogeneous (true);
532 Button* edit_group_add_button = manage (new Button ());
533 Button* edit_group_remove_button = manage (new Button ());
537 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
539 edit_group_add_button->add (*w);
541 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
543 edit_group_remove_button->add (*w);
545 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
546 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
548 edit_group_display_button_box->pack_start (*edit_group_add_button);
549 edit_group_display_button_box->pack_start (*edit_group_remove_button);
551 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
552 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
554 region_list_display.set_size_request (100, -1);
555 region_list_display.set_name ("RegionListDisplay");
557 region_list_model = TreeStore::create (region_list_columns);
558 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
559 region_list_model->set_sort_column (0, SORT_ASCENDING);
561 region_list_display.set_model (region_list_model);
562 region_list_display.append_column (_("Regions"), region_list_columns.name);
563 region_list_display.set_headers_visible (false);
565 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
567 TreeViewColumn* tv_col = region_list_display.get_column(0);
568 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
569 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
570 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
572 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
573 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
575 /* setup DnD handling */
577 list<TargetEntry> region_list_target_table;
579 region_list_target_table.push_back (TargetEntry ("text/plain"));
580 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
581 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
583 region_list_display.add_drop_targets (region_list_target_table);
584 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
586 region_list_scroller.add (region_list_display);
587 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
589 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
590 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
591 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
592 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
593 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
594 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
596 named_selection_scroller.add (named_selection_display);
597 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
599 named_selection_model = TreeStore::create (named_selection_columns);
600 named_selection_display.set_model (named_selection_model);
601 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
602 named_selection_display.set_headers_visible (false);
603 named_selection_display.set_size_request (100, -1);
604 named_selection_display.set_name ("NamedSelectionDisplay");
606 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
607 named_selection_display.set_size_request (100, -1);
608 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
609 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
610 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
614 snapshot_display_model = ListStore::create (snapshot_display_columns);
615 snapshot_display.set_model (snapshot_display_model);
616 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
617 snapshot_display.set_name ("SnapshotDisplay");
618 snapshot_display.set_size_request (75, -1);
619 snapshot_display.set_headers_visible (false);
620 snapshot_display.set_reorderable (false);
621 snapshot_display_scroller.add (snapshot_display);
622 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
624 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
625 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
629 nlabel = manage (new Label (_("Regions")));
630 nlabel->set_angle (-90);
631 the_notebook.append_page (region_list_scroller, *nlabel);
632 nlabel = manage (new Label (_("Tracks/Busses")));
633 nlabel->set_angle (-90);
634 the_notebook.append_page (route_list_scroller, *nlabel);
635 nlabel = manage (new Label (_("Snapshots")));
636 nlabel->set_angle (-90);
637 the_notebook.append_page (snapshot_display_scroller, *nlabel);
638 nlabel = manage (new Label (_("Edit Groups")));
639 nlabel->set_angle (-90);
640 the_notebook.append_page (*edit_group_display_packer, *nlabel);
641 nlabel = manage (new Label (_("Chunks")));
642 nlabel->set_angle (-90);
643 the_notebook.append_page (named_selection_scroller, *nlabel);
645 the_notebook.set_show_tabs (true);
646 the_notebook.set_scrollable (true);
647 the_notebook.popup_enable ();
648 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
650 post_maximal_editor_width = 0;
651 post_maximal_pane_position = 0;
652 edit_pane.pack1 (edit_packer, true, true);
653 edit_pane.pack2 (the_notebook, false, true);
655 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
657 top_hbox.pack_start (toolbar_frame, true, true);
659 HBox *hbox = manage (new HBox);
660 hbox->pack_start (edit_pane, true, true);
662 global_vpacker.pack_start (top_hbox, false, false);
663 global_vpacker.pack_start (*hbox, true, true);
665 global_hpacker.pack_start (global_vpacker, true, true);
667 set_name ("EditorWindow");
668 add_accel_group (ActionManager::ui_manager->get_accel_group());
670 vpacker.pack_end (global_hpacker, true, true);
672 /* register actions now so that set_state() can find them and set toggles/checks etc */
676 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
679 _playlist_selector = new PlaylistSelector();
680 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
682 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
686 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
687 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
689 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
690 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
692 nudge_forward_button.set_name ("TransportButton");
693 nudge_backward_button.set_name ("TransportButton");
695 fade_context_menu.set_name ("ArdourContextMenu");
697 /* icons, titles, WM stuff */
699 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
700 Glib::RefPtr<Gdk::Pixbuf> icon;
702 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
703 window_icons.push_back (icon);
705 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
706 window_icons.push_back (icon);
708 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
709 window_icons.push_back (icon);
711 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
712 window_icons.push_back (icon);
714 if (!window_icons.empty()) {
715 set_icon_list (window_icons);
716 set_default_icon_list (window_icons);
719 WindowTitle title(Glib::get_application_name());
720 title += _("Editor");
721 set_title (title.get_string());
722 set_wmclass (X_("ardour_editor"), "Ardour");
725 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
727 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
728 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
730 /* allow external control surfaces/protocols to do various things */
732 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
733 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
734 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
735 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
737 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
746 if(image_socket_listener)
748 if(image_socket_listener->is_connected())
750 image_socket_listener->close_connection() ;
753 delete image_socket_listener ;
754 image_socket_listener = 0 ;
760 Editor::add_toplevel_controls (Container& cont)
762 vpacker.pack_start (cont, false, false);
767 Editor::catch_vanishing_regionview (RegionView *rv)
769 /* note: the selection will take care of the vanishing
770 audioregionview by itself.
773 if (clicked_regionview == rv) {
774 clicked_regionview = 0;
777 if (entered_regionview == rv) {
778 set_entered_regionview (0);
783 Editor::set_entered_regionview (RegionView* rv)
785 if (rv == entered_regionview) {
789 if (entered_regionview) {
790 entered_regionview->exited ();
793 if ((entered_regionview = rv) != 0) {
794 entered_regionview->entered ();
799 Editor::set_entered_track (TimeAxisView* tav)
802 entered_track->exited ();
805 if ((entered_track = tav) != 0) {
806 entered_track->entered ();
811 Editor::show_window ()
816 /* now reset all audio_time_axis heights, because widgets might need
822 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
823 tv = (static_cast<TimeAxisView*>(*i));
829 Editor::tie_vertical_scrolling ()
831 double y1 = vertical_adjustment.get_value();
832 controls_layout.get_vadjustment()->set_value (y1);
833 playhead_cursor->set_y_axis(y1);
834 edit_cursor->set_y_axis(y1);
838 Editor::instant_save ()
840 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
845 session->add_instant_xml(get_state(), session->path());
847 Config->add_instant_xml(get_state(), get_user_ardour_path());
852 Editor::edit_cursor_clock_changed()
854 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
855 edit_cursor->set_position (edit_cursor_clock.current_time());
861 Editor::zoom_adjustment_changed ()
867 double fpu = zoom_range_clock.current_duration() / canvas_width;
871 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
872 } else if (fpu > session->current_end_frame() / canvas_width) {
873 fpu = session->current_end_frame() / canvas_width;
874 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
881 Editor::control_scroll (float fraction)
883 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
889 double step = fraction * current_page_frames();
892 if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
894 } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
895 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
897 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
900 /* move visuals, we'll catch up with it later */
902 playhead_cursor->set_position (target);
904 if (target > (current_page_frames() / 2)) {
905 /* try to center PH in window */
906 reset_x_origin (target - (current_page_frames()/2));
911 /* cancel the existing */
913 control_scroll_connection.disconnect ();
915 /* add the next one */
917 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
921 Editor::deferred_control_scroll (nframes_t target)
923 session->request_locate (target);
928 Editor::on_realize ()
930 Window::on_realize ();
935 Editor::start_scrolling ()
937 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
938 (mem_fun(*this, &Editor::update_current_screen));
942 Editor::stop_scrolling ()
944 scroll_connection.disconnect ();
948 Editor::map_position_change (nframes_t frame)
950 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
952 if (session == 0 || !_follow_playhead) {
956 center_screen (frame);
957 playhead_cursor->set_position (frame);
961 Editor::center_screen (nframes_t frame)
963 double page = canvas_width * frames_per_unit;
965 /* if we're off the page, then scroll.
968 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
969 center_screen_internal (frame, page);
974 Editor::center_screen_internal (nframes_t frame, float page)
979 frame -= (nframes_t) page;
984 reset_x_origin (frame);
988 Editor::handle_new_duration ()
990 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
992 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
994 if (new_end > last_canvas_frame) {
995 last_canvas_frame = new_end;
996 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
997 reset_scrolling_region ();
1000 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1004 Editor::update_title_s (const string & snap_name)
1006 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1012 Editor::update_title ()
1014 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1017 bool dirty = session->dirty();
1019 string session_name;
1021 if (session->snap_name() != session->name()) {
1022 session_name = session->snap_name();
1024 session_name = session->name();
1028 session_name = "*" + session_name;
1031 WindowTitle title(session_name);
1032 title += Glib::get_application_name();
1033 set_title (title.get_string());
1038 Editor::connect_to_session (Session *t)
1042 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1045 /* catch up with the playhead */
1047 session->request_locate (playhead_cursor->current_frame);
1049 if (first_action_message) {
1050 first_action_message->hide();
1055 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1056 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1058 /* These signals can all be emitted by a non-GUI thread. Therefore the
1059 handlers for them must not attempt to directly interact with the GUI,
1060 but use Gtkmm2ext::UI::instance()->call_slot();
1063 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1064 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1065 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1066 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1067 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1068 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1069 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1070 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1071 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1072 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1073 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1074 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1075 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1076 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1078 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1080 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1082 edit_groups_changed ();
1084 edit_cursor_clock.set_session (session);
1085 zoom_range_clock.set_session (session);
1086 _playlist_selector->set_session (session);
1087 nudge_clock.set_session (session);
1090 if (analysis_window != 0)
1091 analysis_window->set_session (session);
1094 Location* loc = session->locations()->auto_loop_location();
1096 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1097 if (loc->start() == loc->end()) {
1098 loc->set_end (loc->start() + 1);
1100 session->locations()->add (loc, false);
1101 session->set_auto_loop_location (loc);
1104 loc->set_name (_("Loop"));
1107 loc = session->locations()->auto_punch_location();
1109 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1110 if (loc->start() == loc->end()) {
1111 loc->set_end (loc->start() + 1);
1113 session->locations()->add (loc, false);
1114 session->set_auto_punch_location (loc);
1117 loc->set_name (_("Punch"));
1120 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1122 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1124 refresh_location_display ();
1125 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1126 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1127 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1128 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1129 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1131 handle_new_duration ();
1133 redisplay_regions ();
1134 redisplay_named_selections ();
1135 redisplay_snapshots ();
1137 initial_route_list_display ();
1139 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1140 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1143 restore_ruler_visibility ();
1144 //tempo_map_changed (Change (0));
1145 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1149 /* don't show master bus in a new session */
1151 if (ARDOUR_UI::instance()->session_is_new ()) {
1153 TreeModel::Children rows = route_display_model->children();
1154 TreeModel::Children::iterator i;
1156 no_route_list_redisplay = true;
1158 for (i = rows.begin(); i != rows.end(); ++i) {
1159 TimeAxisView *tv = (*i)[route_display_columns.tv];
1160 RouteTimeAxisView *rtv;
1162 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1163 if (rtv->route()->master()) {
1164 route_list_display.get_selection()->unselect (i);
1169 no_route_list_redisplay = false;
1170 redisplay_route_list ();
1173 /* register for undo history */
1175 session->register_with_memento_command_factory(_id, this);
1179 Editor::build_cursors ()
1181 using namespace Gdk;
1183 Gdk::Color mbg ("#000000" ); /* Black */
1184 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1187 RefPtr<Bitmap> source, mask;
1188 source = Bitmap::create (mag_bits, mag_width, mag_height);
1189 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1190 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1193 Gdk::Color fbg ("#ffffff" );
1194 Gdk::Color ffg ("#000000" );
1197 RefPtr<Bitmap> source, mask;
1199 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1200 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1201 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1205 RefPtr<Bitmap> source, mask;
1206 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1207 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1208 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1211 grabber_cursor = new Gdk::Cursor (HAND2);
1212 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1213 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1214 selector_cursor = new Gdk::Cursor (XTERM);
1215 time_fx_cursor = new Gdk::Cursor (SIZING);
1216 wait_cursor = new Gdk::Cursor (WATCH);
1217 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1220 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1222 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1224 using namespace Menu_Helpers;
1225 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1228 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1232 MenuList& items (fade_context_menu.items());
1236 switch (item_type) {
1238 case FadeInHandleItem:
1239 if (arv->audio_region()->fade_in_active()) {
1240 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1242 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1245 items.push_back (SeparatorElem());
1247 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1248 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1249 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1250 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1251 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1255 case FadeOutHandleItem:
1256 if (arv->audio_region()->fade_out_active()) {
1257 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1259 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1262 items.push_back (SeparatorElem());
1264 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1265 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1266 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1267 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1268 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1273 fatal << _("programming error: ")
1274 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1279 fade_context_menu.popup (button, time);
1282 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1284 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1286 build_track_context_menu (frame)->popup (button, time);
1290 Editor::build_track_context_menu (nframes_t frame)
1292 using namespace Menu_Helpers;
1294 Menu* menu = manage (new Menu);
1295 MenuList& edit_items = menu->items();
1298 /* Build the general `track' context menu, adding what is appropriate given
1299 the current selection */
1301 /* XXX: currently crossfades can't be selected, so we can't use the selection
1302 to decide which crossfades to mention in the menu. I believe this will
1303 change at some point. For now we have to use clicked_trackview to decide. */
1304 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1307 boost::shared_ptr<Diskstream> ds;
1308 boost::shared_ptr<Playlist> pl;
1309 boost::shared_ptr<AudioPlaylist> apl;
1311 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1313 AudioPlaylist::Crossfades xfades;
1314 apl->crossfades_at (frame, xfades);
1316 bool many = xfades.size() > 1;
1318 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1319 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1324 if (!selection->time.empty()) {
1325 add_selection_context_items (edit_items);
1328 if (!selection->regions.empty()) {
1329 add_region_context_items (edit_items);
1332 if (!selection->tracks.empty()) {
1333 add_bus_or_audio_track_context_items (edit_items);
1336 menu->set_name ("ArdourContextMenu");
1343 Editor::analyze_region_selection()
1345 if (analysis_window == 0) {
1346 analysis_window = new AnalysisWindow();
1349 analysis_window->set_session(session);
1351 analysis_window->show_all();
1354 analysis_window->set_regionmode();
1355 analysis_window->analyze();
1357 analysis_window->present();
1361 Editor::analyze_range_selection()
1363 if (analysis_window == 0) {
1364 analysis_window = new AnalysisWindow();
1367 analysis_window->set_session(session);
1369 analysis_window->show_all();
1372 analysis_window->set_rangemode();
1373 analysis_window->analyze();
1375 analysis_window->present();
1377 #endif /* FFT_ANALYSIS */
1380 /** Add context menu items relevant to crossfades.
1381 * @param edit_items List to add the items to.
1384 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1386 using namespace Menu_Helpers;
1387 Menu *xfade_menu = manage (new Menu);
1388 MenuList& items = xfade_menu->items();
1389 xfade_menu->set_name ("ArdourContextMenu");
1392 if (xfade->active()) {
1398 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1399 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1401 if (xfade->can_follow_overlap()) {
1403 if (xfade->following_overlap()) {
1404 str = _("Convert to short");
1406 str = _("Convert to full");
1409 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1413 str = xfade->out()->name();
1415 str += xfade->in()->name();
1417 str = _("Crossfade");
1420 edit_items.push_back (MenuElem (str, *xfade_menu));
1421 edit_items.push_back (SeparatorElem());
1425 Editor::xfade_edit_left_region ()
1427 if (clicked_crossfadeview) {
1428 clicked_crossfadeview->left_view.show_region_editor ();
1433 Editor::xfade_edit_right_region ()
1435 if (clicked_crossfadeview) {
1436 clicked_crossfadeview->right_view.show_region_editor ();
1440 /** Add an element to a menu, settings its sensitivity.
1441 * @param m Menu to add to.
1442 * @param e Element to add.
1443 * @param s true to make sensitive, false to make insensitive
1446 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1450 m.back().set_sensitive (false);
1454 /** Add context menu items relevant to regions.
1455 * @param edit_items List to add the items to.
1458 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1460 using namespace Menu_Helpers;
1461 Menu *region_menu = manage (new Menu);
1462 MenuList& items = region_menu->items();
1463 region_menu->set_name ("ArdourContextMenu");
1465 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1466 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1467 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1469 Menu* sync_point_menu = manage (new Menu);
1470 MenuList& sync_point_items = sync_point_menu->items();
1471 sync_point_menu->set_name("ArdourContextMenu");
1473 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1474 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1476 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1478 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1480 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1482 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1485 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1488 items.push_back (SeparatorElem());
1490 items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1491 items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1492 items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1493 items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1494 items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1495 items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1496 items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1497 items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1499 /* We allow "Original position" if at least one region is not at its
1502 RegionSelection::iterator i = selection->regions.begin();
1503 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1507 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1509 items.push_back (SeparatorElem());
1511 /* Find out if we have a selected audio region */
1512 i = selection->regions.begin();
1513 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1516 bool const have_selected_audio_region = (i != selection->regions.end());
1518 if (have_selected_audio_region) {
1520 Menu* envelopes_menu = manage (new Menu);
1521 MenuList& envelopes_items = envelopes_menu->items();
1522 envelopes_menu->set_name ("ArdourContextMenu");
1524 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1525 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1526 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1527 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1528 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1530 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1532 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1533 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1536 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
1537 items.push_back (SeparatorElem());
1540 /* range related stuff */
1542 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1544 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1546 items.push_back (SeparatorElem());
1550 Menu *nudge_menu = manage (new Menu());
1551 MenuList& nudge_items = nudge_menu->items();
1552 nudge_menu->set_name ("ArdourContextMenu");
1554 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1555 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1556 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1557 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1559 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1561 Menu *trim_menu = manage (new Menu);
1562 MenuList& trim_items = trim_menu->items();
1563 trim_menu->set_name ("ArdourContextMenu");
1565 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1566 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1568 items.push_back (MenuElem (_("Trim"), *trim_menu));
1569 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1570 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1571 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1572 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1573 items.push_back (SeparatorElem());
1574 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1576 /* OK, stick the region submenu at the top of the list, and then add
1580 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1581 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1584 /** Add context menu items relevant to selection ranges.
1585 * @param edit_items List to add the items to.
1588 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1590 using namespace Menu_Helpers;
1591 Menu *selection_menu = manage (new Menu);
1592 MenuList& items = selection_menu->items();
1593 selection_menu->set_name ("ArdourContextMenu");
1595 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1596 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1599 items.push_back (SeparatorElem());
1600 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1603 items.push_back (SeparatorElem());
1604 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1605 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1607 items.push_back (SeparatorElem());
1608 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1609 items.push_back (SeparatorElem());
1610 items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1611 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1612 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1613 items.push_back (SeparatorElem());
1614 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1615 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1616 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1617 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1618 items.push_back (SeparatorElem());
1619 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1620 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1622 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1623 edit_items.push_back (SeparatorElem());
1626 /** Add context menu items relevant to busses or audio tracks.
1627 * @param edit_items List to add the items to.
1630 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1632 using namespace Menu_Helpers;
1634 /* We add every possible action here, and de-sensitize things
1635 that aren't allowed. The sensitivity logic is a bit spread out;
1636 on the one hand I'm using things like can_cut_copy (), which is
1637 reasonably complicated and so perhaps better near the function that
1638 it expresses sensitivity for, and on the other hand checks
1639 in this function as well. You can't really have can_* for everything
1640 or the number of methods would get silly. */
1642 bool const one_selected_region = selection->regions.size() == 1;
1644 /* Count the number of selected audio tracks */
1645 int n_audio_tracks = 0;
1646 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1647 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1648 if (r && r->is_audio_track()) {
1655 Menu *play_menu = manage (new Menu);
1656 MenuList& play_items = play_menu->items();
1657 play_menu->set_name ("ArdourContextMenu");
1659 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1660 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1661 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1663 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1665 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1669 Menu *select_menu = manage (new Menu);
1670 MenuList& select_items = select_menu->items();
1671 select_menu->set_name ("ArdourContextMenu");
1673 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1675 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1677 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1679 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1681 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1683 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1684 select_items.push_back (SeparatorElem());
1686 if (n_audio_tracks) {
1687 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1688 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1691 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1692 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1693 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1694 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1696 if (n_audio_tracks) {
1697 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1700 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1704 Menu *cutnpaste_menu = manage (new Menu);
1705 MenuList& cutnpaste_items = cutnpaste_menu->items();
1706 cutnpaste_menu->set_name ("ArdourContextMenu");
1708 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1710 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1712 if (n_audio_tracks) {
1713 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1714 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1716 cutnpaste_items.push_back (SeparatorElem());
1718 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1719 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1720 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1722 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1725 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1727 if (n_audio_tracks) {
1729 Menu *track_menu = manage (new Menu);
1730 MenuList& track_items = track_menu->items();
1731 track_menu->set_name ("ArdourContextMenu");
1733 /* Adding new material */
1735 add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1737 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1741 Menu *nudge_menu = manage (new Menu());
1742 MenuList& nudge_items = nudge_menu->items();
1743 nudge_menu->set_name ("ArdourContextMenu");
1745 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1746 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1748 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1750 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1752 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1754 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1756 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1758 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1760 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1763 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1764 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1766 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1767 edit_items.push_back (MenuElem (str, *track_menu));
1771 /* CURSOR SETTING AND MARKS AND STUFF */
1774 Editor::set_snap_to (SnapType st)
1777 string str = snap_type_strings[(int) st];
1779 if (str != snap_type_selector.get_active_text()) {
1780 snap_type_selector.set_active_text (str);
1785 switch (snap_type) {
1786 case SnapToAThirtysecondBeat:
1787 case SnapToASixteenthBeat:
1788 case SnapToAEighthBeat:
1789 case SnapToAQuarterBeat:
1790 case SnapToAThirdBeat:
1791 update_tempo_based_rulers ();
1799 Editor::set_snap_mode (SnapMode mode)
1802 string str = snap_mode_strings[(int)mode];
1804 if (str != snap_mode_selector.get_active_text ()) {
1805 snap_mode_selector.set_active_text (str);
1812 Editor::set_state (const XMLNode& node)
1814 const XMLProperty* prop;
1816 int x, y, xoff, yoff;
1819 if ((prop = node.property ("id")) != 0) {
1820 _id = prop->value ();
1823 if ((geometry = find_named_node (node, "geometry")) == 0) {
1825 g.base_width = default_width;
1826 g.base_height = default_height;
1834 g.base_width = atoi(geometry->property("x_size")->value());
1835 g.base_height = atoi(geometry->property("y_size")->value());
1836 x = atoi(geometry->property("x_pos")->value());
1837 y = atoi(geometry->property("y_pos")->value());
1838 xoff = atoi(geometry->property("x_off")->value());
1839 yoff = atoi(geometry->property("y_off")->value());
1842 set_default_size (g.base_width, g.base_height);
1845 if (session && (prop = node.property ("playhead"))) {
1846 nframes_t pos = atol (prop->value().c_str());
1847 playhead_cursor->set_position (pos);
1849 playhead_cursor->set_position (0);
1851 /* reset_x_origin() doesn't work right here, since the old
1852 position may be zero already, and it does nothing in such
1857 horizontal_adjustment.set_value (0);
1860 if (session && (prop = node.property ("edit-cursor"))) {
1861 nframes_t pos = atol (prop->value().c_str());
1862 edit_cursor->set_position (pos);
1864 edit_cursor->set_position (0);
1867 if ((prop = node.property ("mixer-width"))) {
1868 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1871 if ((prop = node.property ("zoom-focus"))) {
1872 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1875 if ((prop = node.property ("zoom"))) {
1876 reset_zoom (PBD::atof (prop->value()));
1879 if ((prop = node.property ("snap-to"))) {
1880 set_snap_to ((SnapType) atoi (prop->value()));
1883 if ((prop = node.property ("snap-mode"))) {
1884 set_snap_mode ((SnapMode) atoi (prop->value()));
1887 if ((prop = node.property ("mouse-mode"))) {
1888 MouseMode m = str2mousemode(prop->value());
1889 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1890 set_mouse_mode (m, true);
1892 mouse_mode = MouseGain; /* lie, to force the mode switch */
1893 set_mouse_mode (MouseObject, true);
1896 if ((prop = node.property ("show-waveforms"))) {
1897 bool yn = (prop->value() == "yes");
1898 _show_waveforms = !yn;
1899 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1901 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1902 /* do it twice to force the change */
1903 tact->set_active (!yn);
1904 tact->set_active (yn);
1908 if ((prop = node.property ("show-waveforms-recording"))) {
1909 bool yn = (prop->value() == "yes");
1910 _show_waveforms_recording = !yn;
1911 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1913 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1914 /* do it twice to force the change */
1915 tact->set_active (!yn);
1916 tact->set_active (yn);
1920 if ((prop = node.property ("show-measures"))) {
1921 bool yn = (prop->value() == "yes");
1922 _show_measures = !yn;
1923 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1925 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1926 /* do it twice to force the change */
1927 tact->set_active (!yn);
1928 tact->set_active (yn);
1932 if ((prop = node.property ("follow-playhead"))) {
1933 bool yn = (prop->value() == "yes");
1934 set_follow_playhead (yn);
1935 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1937 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1938 if (tact->get_active() != yn) {
1939 tact->set_active (yn);
1944 if ((prop = node.property ("region-list-sort-type"))) {
1945 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
1946 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1949 if ((prop = node.property ("xfades-visible"))) {
1950 bool yn = (prop->value() == "yes");
1951 _xfade_visibility = !yn;
1952 // set_xfade_visibility (yn);
1955 if ((prop = node.property ("show-editor-mixer"))) {
1957 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1960 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1961 bool yn = (prop->value() == X_("yes"));
1963 /* do it twice to force the change */
1965 tact->set_active (!yn);
1966 tact->set_active (yn);
1975 Editor::get_state ()
1977 XMLNode* node = new XMLNode ("Editor");
1980 _id.print (buf, sizeof (buf));
1981 node->add_property ("id", buf);
1983 if (is_realized()) {
1984 Glib::RefPtr<Gdk::Window> win = get_window();
1986 int x, y, xoff, yoff, width, height;
1987 win->get_root_origin(x, y);
1988 win->get_position(xoff, yoff);
1989 win->get_size(width, height);
1991 XMLNode* geometry = new XMLNode ("geometry");
1993 snprintf(buf, sizeof(buf), "%d", width);
1994 geometry->add_property("x_size", string(buf));
1995 snprintf(buf, sizeof(buf), "%d", height);
1996 geometry->add_property("y_size", string(buf));
1997 snprintf(buf, sizeof(buf), "%d", x);
1998 geometry->add_property("x_pos", string(buf));
1999 snprintf(buf, sizeof(buf), "%d", y);
2000 geometry->add_property("y_pos", string(buf));
2001 snprintf(buf, sizeof(buf), "%d", xoff);
2002 geometry->add_property("x_off", string(buf));
2003 snprintf(buf, sizeof(buf), "%d", yoff);
2004 geometry->add_property("y_off", string(buf));
2005 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2006 geometry->add_property("edit_pane_pos", string(buf));
2008 node->add_child_nocopy (*geometry);
2011 maybe_add_mixer_strip_width (*node);
2013 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2014 node->add_property ("zoom-focus", buf);
2015 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2016 node->add_property ("zoom", buf);
2017 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2018 node->add_property ("snap-to", buf);
2019 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2020 node->add_property ("snap-mode", buf);
2022 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2023 node->add_property ("playhead", buf);
2024 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2025 node->add_property ("edit-cursor", buf);
2027 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2028 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2029 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2030 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2031 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2032 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2033 node->add_property ("mouse-mode", enum2str(mouse_mode));
2035 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2037 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2038 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2047 Editor::trackview_by_y_position (double y)
2049 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2053 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2062 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2064 Location* before = 0;
2065 Location* after = 0;
2071 const nframes64_t one_second = session->frame_rate();
2072 const nframes64_t one_minute = session->frame_rate() * 60;
2073 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2074 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2075 nframes64_t presnap = start;
2077 switch (snap_type) {
2083 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2085 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2089 case SnapToSMPTEFrame:
2090 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2091 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2093 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2097 case SnapToSMPTESeconds:
2098 if (session->smpte_offset_negative())
2100 start += session->smpte_offset ();
2102 start -= session->smpte_offset ();
2104 if (start % one_smpte_second > one_smpte_second / 2) {
2105 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2107 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2110 if (session->smpte_offset_negative())
2112 start -= session->smpte_offset ();
2114 start += session->smpte_offset ();
2118 case SnapToSMPTEMinutes:
2119 if (session->smpte_offset_negative())
2121 start += session->smpte_offset ();
2123 start -= session->smpte_offset ();
2125 if (start % one_smpte_minute > one_smpte_minute / 2) {
2126 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2128 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2130 if (session->smpte_offset_negative())
2132 start -= session->smpte_offset ();
2134 start += session->smpte_offset ();
2139 if (start % one_second > one_second / 2) {
2140 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2142 start = (nframes_t) floor ((double) start / one_second) * one_second;
2147 if (start % one_minute > one_minute / 2) {
2148 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2150 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2155 start = session->tempo_map().round_to_bar (start, direction);
2159 start = session->tempo_map().round_to_beat (start, direction);
2162 case SnapToAThirtysecondBeat:
2163 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2166 case SnapToASixteenthBeat:
2167 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2170 case SnapToAEighthBeat:
2171 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2174 case SnapToAQuarterBeat:
2175 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2178 case SnapToAThirdBeat:
2179 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2182 case SnapToEditCursor:
2183 start = edit_cursor->current_frame;
2191 before = session->locations()->first_location_before (start);
2192 after = session->locations()->first_location_after (start);
2194 if (direction < 0) {
2196 start = before->start();
2200 } else if (direction > 0) {
2202 start = after->start();
2204 start = session->current_end_frame();
2209 /* find nearest of the two */
2210 if ((start - before->start()) < (after->start() - start)) {
2211 start = before->start();
2213 start = after->start();
2216 start = before->start();
2219 start = after->start();
2226 case SnapToRegionStart:
2227 case SnapToRegionEnd:
2228 case SnapToRegionSync:
2229 case SnapToRegionBoundary:
2230 if (!region_boundary_cache.empty()) {
2231 vector<nframes_t>::iterator i;
2233 if (direction > 0) {
2234 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2236 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2239 if (i != region_boundary_cache.end()) {
2242 start = region_boundary_cache.back();
2248 switch (snap_mode) {
2254 if (presnap > start) {
2255 if (presnap > (start + unit_to_frame(snap_threshold))) {
2259 } else if (presnap < start) {
2260 if (presnap < (start - unit_to_frame(snap_threshold))) {
2272 Editor::setup_toolbar ()
2276 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2279 /* Mode Buttons (tool selection) */
2281 vector<ToggleButton *> mouse_mode_buttons;
2283 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2284 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2285 mouse_mode_buttons.push_back (&mouse_move_button);
2286 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2287 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2288 mouse_mode_buttons.push_back (&mouse_select_button);
2289 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2290 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2291 mouse_mode_buttons.push_back (&mouse_gain_button);
2292 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2293 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2294 mouse_mode_buttons.push_back (&mouse_zoom_button);
2295 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2296 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2297 mouse_mode_buttons.push_back (&mouse_timefx_button);
2298 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2299 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2300 mouse_mode_buttons.push_back (&mouse_audition_button);
2302 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2304 HBox* mode_box = manage(new HBox);
2305 mode_box->set_border_width (2);
2306 mode_box->set_spacing(4);
2307 mouse_mode_button_box.set_spacing(1);
2308 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2309 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2310 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2311 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2312 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2313 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2314 mouse_mode_button_box.set_homogeneous(true);
2316 vector<string> edit_mode_strings;
2317 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2318 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2320 edit_mode_selector.set_name ("EditModeSelector");
2321 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2322 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2323 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2325 mode_box->pack_start(edit_mode_selector);
2326 mode_box->pack_start(mouse_mode_button_box);
2328 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2329 mouse_mode_tearoff->set_name ("MouseModeBase");
2331 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2332 &mouse_mode_tearoff->tearoff_window()));
2333 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2334 &mouse_mode_tearoff->tearoff_window(), 1));
2335 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2336 &mouse_mode_tearoff->tearoff_window()));
2337 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2338 &mouse_mode_tearoff->tearoff_window(), 1));
2340 mouse_move_button.set_name ("MouseModeButton");
2341 mouse_select_button.set_name ("MouseModeButton");
2342 mouse_gain_button.set_name ("MouseModeButton");
2343 mouse_zoom_button.set_name ("MouseModeButton");
2344 mouse_timefx_button.set_name ("MouseModeButton");
2345 mouse_audition_button.set_name ("MouseModeButton");
2347 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2348 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2349 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2350 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2351 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2352 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2354 mouse_move_button.unset_flags (CAN_FOCUS);
2355 mouse_select_button.unset_flags (CAN_FOCUS);
2356 mouse_gain_button.unset_flags (CAN_FOCUS);
2357 mouse_zoom_button.unset_flags (CAN_FOCUS);
2358 mouse_timefx_button.unset_flags (CAN_FOCUS);
2359 mouse_audition_button.unset_flags (CAN_FOCUS);
2361 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2362 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2364 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2365 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2366 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2367 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2368 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2370 // mouse_move_button.set_active (true);
2375 zoom_box.set_spacing (1);
2376 zoom_box.set_border_width (2);
2378 zoom_in_button.set_name ("EditorTimeButton");
2379 zoom_in_button.set_size_request(-1,16);
2380 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2381 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2382 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2384 zoom_out_button.set_name ("EditorTimeButton");
2385 zoom_out_button.set_size_request(-1,16);
2386 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2387 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2388 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2390 zoom_out_full_button.set_name ("EditorTimeButton");
2391 zoom_out_full_button.set_size_request(-1,16);
2392 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2393 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2394 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2396 zoom_focus_selector.set_name ("ZoomFocusSelector");
2397 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0);
2398 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2399 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2400 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2402 zoom_box.pack_start (zoom_focus_selector, true, true);
2403 zoom_box.pack_start (zoom_out_button, false, false);
2404 zoom_box.pack_start (zoom_in_button, false, false);
2405 zoom_box.pack_start (zoom_out_full_button, false, false);
2407 /* Edit Cursor / Snap */
2409 snap_box.set_spacing (1);
2410 snap_box.set_border_width (2);
2412 snap_type_selector.set_name ("SnapTypeSelector");
2413 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2414 set_popdown_strings (snap_type_selector, snap_type_strings);
2415 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2416 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2418 snap_mode_selector.set_name ("SnapModeSelector");
2419 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2420 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2421 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2423 snap_box.pack_start (edit_cursor_clock, false, false);
2424 snap_box.pack_start (snap_mode_selector, false, false);
2425 snap_box.pack_start (snap_type_selector, false, false);
2430 HBox *nudge_box = manage (new HBox);
2431 nudge_box->set_spacing(1);
2432 nudge_box->set_border_width (2);
2434 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2435 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2437 nudge_box->pack_start (nudge_backward_button, false, false);
2438 nudge_box->pack_start (nudge_forward_button, false, false);
2439 nudge_box->pack_start (nudge_clock, false, false);
2442 /* Pack everything in... */
2444 HBox* hbox = new HBox;
2445 hbox->set_spacing(10);
2447 tools_tearoff = new TearOff (*hbox);
2448 tools_tearoff->set_name ("MouseModeBase");
2450 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2451 &tools_tearoff->tearoff_window()));
2452 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2453 &tools_tearoff->tearoff_window(), 0));
2454 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2455 &tools_tearoff->tearoff_window()));
2456 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2457 &tools_tearoff->tearoff_window(), 0));
2459 toolbar_hbox.set_spacing (10);
2460 toolbar_hbox.set_border_width (1);
2462 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2463 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2466 hbox->pack_start (snap_box, false, false);
2467 // hbox->pack_start (zoom_box, false, false);
2468 hbox->pack_start (*nudge_box, false, false);
2472 toolbar_base.set_name ("ToolBarBase");
2473 toolbar_base.add (toolbar_hbox);
2475 toolbar_frame.set_shadow_type (SHADOW_OUT);
2476 toolbar_frame.set_name ("BaseFrame");
2477 toolbar_frame.add (toolbar_base);
2481 Editor::convert_drop_to_paths (vector<ustring>& paths,
2482 const RefPtr<Gdk::DragContext>& context,
2485 const SelectionData& data,
2494 vector<ustring> uris = data.get_uris();
2498 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2499 are actually URI lists. So do it by hand.
2502 if (data.get_target() != "text/plain") {
2506 /* Parse the "uri-list" format that Nautilus provides,
2507 where each pathname is delimited by \r\n
2510 const char* p = data.get_text().c_str();
2517 while (g_ascii_isspace (*p))
2521 while (*q && (*q != '\n') && (*q != '\r'))
2527 while (q > p && g_ascii_isspace (*q))
2532 uris.push_back (ustring (p, q - p + 1));
2536 p = strchr (p, '\n');
2546 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2547 if ((*i).substr (0,7) == "file://") {
2549 PBD::url_decode (p);
2550 paths.push_back (p.substr (7));
2558 Editor::new_tempo_section ()
2564 Editor::map_transport_state ()
2566 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2568 if (session->transport_stopped()) {
2569 have_pending_keyboard_selection = false;
2572 update_loop_range_view (true);
2577 Editor::State::State ()
2579 selection = new Selection;
2582 Editor::State::~State ()
2588 Editor::get_memento () const
2590 State *state = new State;
2592 store_state (*state);
2593 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2597 Editor::store_state (State& state) const
2599 *state.selection = *selection;
2603 Editor::restore_state (State *state)
2605 if (*selection == *state->selection) {
2609 *selection = *state->selection;
2610 time_selection_changed ();
2611 region_selection_changed ();
2613 /* XXX other selection change handlers? */
2617 Editor::begin_reversible_command (string name)
2620 before = &get_state();
2621 session->begin_reversible_command (name);
2626 Editor::commit_reversible_command ()
2629 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2634 Editor::set_edit_group_solo (Route& route, bool yn)
2636 RouteGroup *edit_group;
2638 if ((edit_group = route.edit_group()) != 0) {
2639 edit_group->apply (&Route::set_solo, yn, this);
2641 route.set_solo (yn, this);
2646 Editor::set_edit_group_mute (Route& route, bool yn)
2648 RouteGroup *edit_group = 0;
2650 if ((edit_group == route.edit_group()) != 0) {
2651 edit_group->apply (&Route::set_mute, yn, this);
2653 route.set_mute (yn, this);
2658 Editor::history_changed ()
2662 if (undo_action && session) {
2663 if (session->undo_depth() == 0) {
2666 label = string_compose(_("Undo (%1)"), session->next_undo());
2668 undo_action->property_label() = label;
2671 if (redo_action && session) {
2672 if (session->redo_depth() == 0) {
2675 label = string_compose(_("Redo (%1)"), session->next_redo());
2677 redo_action->property_label() = label;
2682 Editor::duplicate_dialog (bool dup_region)
2684 if (selection->regions.empty() && (selection->time.length() == 0)) {
2688 ArdourDialog win ("duplicate dialog");
2689 Label label (_("Duplicate how many times?"));
2690 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2691 SpinButton spinner (adjustment);
2693 win.get_vbox()->set_spacing (12);
2694 win.get_vbox()->pack_start (label);
2696 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2697 place, visually. so do this by hand.
2700 win.get_vbox()->pack_start (spinner);
2701 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2706 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2707 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2709 win.set_position (WIN_POS_MOUSE);
2711 spinner.grab_focus ();
2713 switch (win.run ()) {
2714 case RESPONSE_ACCEPT:
2720 float times = adjustment.get_value();
2722 if (!selection->regions.empty()) {
2723 duplicate_some_regions (selection->regions, times);
2725 duplicate_selection (times);
2730 Editor::show_verbose_canvas_cursor ()
2732 verbose_canvas_cursor->raise_to_top();
2733 verbose_canvas_cursor->show();
2734 verbose_cursor_visible = true;
2738 Editor::hide_verbose_canvas_cursor ()
2740 verbose_canvas_cursor->hide();
2741 verbose_cursor_visible = false;
2745 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2747 /* XXX get origin of canvas relative to root window,
2748 add x and y and check compared to gdk_screen_{width,height}
2750 verbose_canvas_cursor->property_text() = txt.c_str();
2751 verbose_canvas_cursor->property_x() = x;
2752 verbose_canvas_cursor->property_y() = y;
2756 Editor::set_verbose_canvas_cursor_text (const string & txt)
2758 verbose_canvas_cursor->property_text() = txt.c_str();
2762 Editor::edit_mode_selection_done ()
2768 string choice = edit_mode_selector.get_active_text();
2769 EditMode mode = Slide;
2771 if (choice == _("Splice Edit")) {
2773 } else if (choice == _("Slide Edit")) {
2777 Config->set_edit_mode (mode);
2781 Editor::snap_type_selection_done ()
2783 string choice = snap_type_selector.get_active_text();
2784 SnapType snaptype = SnapToFrame;
2786 if (choice == _("Beats/3")) {
2787 snaptype = SnapToAThirdBeat;
2788 } else if (choice == _("Beats/4")) {
2789 snaptype = SnapToAQuarterBeat;
2790 } else if (choice == _("Beats/8")) {
2791 snaptype = SnapToAEighthBeat;
2792 } else if (choice == _("Beats/16")) {
2793 snaptype = SnapToASixteenthBeat;
2794 } else if (choice == _("Beats/32")) {
2795 snaptype = SnapToAThirtysecondBeat;
2796 } else if (choice == _("Beats")) {
2797 snaptype = SnapToBeat;
2798 } else if (choice == _("Bars")) {
2799 snaptype = SnapToBar;
2800 } else if (choice == _("Marks")) {
2801 snaptype = SnapToMark;
2802 } else if (choice == _("Edit Cursor")) {
2803 snaptype = SnapToEditCursor;
2804 } else if (choice == _("Region starts")) {
2805 snaptype = SnapToRegionStart;
2806 } else if (choice == _("Region ends")) {
2807 snaptype = SnapToRegionEnd;
2808 } else if (choice == _("Region bounds")) {
2809 snaptype = SnapToRegionBoundary;
2810 } else if (choice == _("Region syncs")) {
2811 snaptype = SnapToRegionSync;
2812 } else if (choice == _("CD Frames")) {
2813 snaptype = SnapToCDFrame;
2814 } else if (choice == _("SMPTE Frames")) {
2815 snaptype = SnapToSMPTEFrame;
2816 } else if (choice == _("SMPTE Seconds")) {
2817 snaptype = SnapToSMPTESeconds;
2818 } else if (choice == _("SMPTE Minutes")) {
2819 snaptype = SnapToSMPTEMinutes;
2820 } else if (choice == _("Seconds")) {
2821 snaptype = SnapToSeconds;
2822 } else if (choice == _("Minutes")) {
2823 snaptype = SnapToMinutes;
2824 } else if (choice == _("None")) {
2825 snaptype = SnapToFrame;
2828 RefPtr<RadioAction> ract = snap_type_action (snaptype);
2830 ract->set_active ();
2835 Editor::snap_mode_selection_done ()
2837 string choice = snap_mode_selector.get_active_text();
2838 SnapMode mode = SnapNormal;
2840 if (choice == _("Normal")) {
2842 } else if (choice == _("Magnetic")) {
2843 mode = SnapMagnetic;
2846 RefPtr<RadioAction> ract = snap_mode_action (mode);
2849 ract->set_active (true);
2854 Editor::zoom_focus_selection_done ()
2856 string choice = zoom_focus_selector.get_active_text();
2857 ZoomFocus focus_type = ZoomFocusLeft;
2859 if (choice == _("Left")) {
2860 focus_type = ZoomFocusLeft;
2861 } else if (choice == _("Right")) {
2862 focus_type = ZoomFocusRight;
2863 } else if (choice == _("Center")) {
2864 focus_type = ZoomFocusCenter;
2865 } else if (choice == _("Playhead")) {
2866 focus_type = ZoomFocusPlayhead;
2867 } else if (choice == _("Edit Cursor")) {
2868 focus_type = ZoomFocusEdit;
2871 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
2874 ract->set_active ();
2879 Editor::edit_controls_button_release (GdkEventButton* ev)
2881 if (Keyboard::is_context_menu_event (ev)) {
2882 ARDOUR_UI::instance()->add_route (this);
2888 Editor::mouse_select_button_release (GdkEventButton* ev)
2890 /* this handles just right-clicks */
2892 if (ev->button != 3) {
2899 Editor::TrackViewList *
2900 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
2903 TrackViewList::iterator i;
2905 v = new TrackViewList;
2907 if (track == 0 && group == 0) {
2911 for (i = track_views.begin(); i != track_views.end (); ++i) {
2915 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
2917 /* just the view for this track
2920 v->push_back (track);
2924 /* views for all tracks in the edit group */
2926 for (i = track_views.begin(); i != track_views.end (); ++i) {
2928 if (group == 0 || (*i)->edit_group() == group) {
2938 Editor::set_zoom_focus (ZoomFocus f)
2940 string str = zoom_focus_strings[(int)f];
2942 if (str != zoom_focus_selector.get_active_text()) {
2943 zoom_focus_selector.set_active_text (str);
2946 if (zoom_focus != f) {
2949 ZoomFocusChanged (); /* EMIT_SIGNAL */
2956 Editor::ensure_float (Window& win)
2958 win.set_transient_for (*this);
2962 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
2964 /* recover or initialize pane positions. do this here rather than earlier because
2965 we don't want the positions to change the child allocations, which they seem to do.
2971 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
2973 static int32_t done;
2976 if ((geometry = find_named_node (*node, "geometry")) == 0) {
2977 width = default_width;
2978 height = default_height;
2980 width = atoi(geometry->property("x_size")->value());
2981 height = atoi(geometry->property("y_size")->value());
2984 if (which == static_cast<Paned*> (&edit_pane)) {
2990 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
2991 /* initial allocation is 90% to canvas, 10% to notebook */
2992 pos = (int) floor (alloc.get_width() * 0.90f);
2993 snprintf (buf, sizeof(buf), "%d", pos);
2995 pos = atoi (prop->value());
2998 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
2999 edit_pane.set_position (pos);
3000 pre_maximal_pane_position = pos;
3006 Editor::detach_tearoff (Box* b, Window* w)
3008 if (tools_tearoff->torn_off() &&
3009 mouse_mode_tearoff->torn_off()) {
3010 top_hbox.remove (toolbar_frame);
3015 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3017 if (toolbar_frame.get_parent() == 0) {
3018 top_hbox.pack_end (toolbar_frame);
3023 Editor::set_show_measures (bool yn)
3025 if (_show_measures != yn) {
3028 if ((_show_measures = yn) == true) {
3036 Editor::toggle_follow_playhead ()
3038 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3040 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3041 set_follow_playhead (tact->get_active());
3046 Editor::set_follow_playhead (bool yn)
3048 if (_follow_playhead != yn) {
3049 if ((_follow_playhead = yn) == true) {
3051 update_current_screen ();
3058 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3060 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3062 xfade->set_active (!xfade->active());
3067 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3069 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3071 xfade->set_follow_overlap (!xfade->following_overlap());
3076 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3078 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3084 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3088 switch (cew.run ()) {
3089 case RESPONSE_ACCEPT:
3096 xfade->StateChanged (Change (~0));
3100 Editor::playlist_selector () const
3102 return *_playlist_selector;
3106 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3110 ret = nudge_clock.current_duration (pos);
3111 next = ret + 1; /* XXXX fix me */
3117 Editor::end_location_changed (Location* location)
3119 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3120 reset_scrolling_region ();
3124 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3126 ArdourDialog dialog ("playlist deletion dialog");
3127 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3128 "If left alone, no audio files used by it will be cleaned.\n"
3129 "If deleted, audio files used by it alone by will cleaned."),
3132 dialog.set_position (WIN_POS_CENTER);
3133 dialog.get_vbox()->pack_start (label);
3137 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3138 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3139 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3141 switch (dialog.run ()) {
3142 case RESPONSE_ACCEPT:
3143 /* delete the playlist */
3147 case RESPONSE_REJECT:
3148 /* keep the playlist */
3160 Editor::audio_region_selection_covers (nframes_t where)
3162 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3163 if ((*a)->region()->covers (where)) {
3172 Editor::prepare_for_cleanup ()
3174 cut_buffer->clear_regions ();
3175 cut_buffer->clear_playlists ();
3177 selection->clear_regions ();
3178 selection->clear_playlists ();
3182 Editor::transport_loop_location()
3185 return session->locations()->auto_loop_location();
3192 Editor::transport_punch_location()
3195 return session->locations()->auto_punch_location();
3202 Editor::control_layout_scroll (GdkEventScroll* ev)
3204 switch (ev->direction) {
3206 scroll_tracks_up_line ();
3210 case GDK_SCROLL_DOWN:
3211 scroll_tracks_down_line ();
3215 /* no left/right handling yet */
3223 /** A new snapshot has been selected.
3226 Editor::snapshot_display_selection_changed ()
3228 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3230 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3232 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3234 if (snap_name.length() == 0) {
3238 if (session->snap_name() == snap_name) {
3242 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3247 Editor::snapshot_display_button_press (GdkEventButton* ev)
3249 if (ev->button == 3) {
3250 /* Right-click on the snapshot list. Work out which snapshot it
3252 Gtk::TreeModel::Path path;
3253 Gtk::TreeViewColumn* col;
3256 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3257 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3259 Gtk::TreeModel::Row row = *iter;
3260 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3269 /** Pop up the snapshot display context menu.
3270 * @param button Button used to open the menu.
3271 * @param time Menu open time.
3272 * @snapshot_name Name of the snapshot that the menu click was over.
3276 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3278 using namespace Menu_Helpers;
3280 MenuList& items (snapshot_context_menu.items());
3283 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3285 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3287 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3289 snapshot_context_menu.popup (button, time);
3293 Editor::rename_snapshot (Glib::ustring old_name)
3295 ArdourPrompter prompter(true);
3299 prompter.set_name ("Prompter");
3300 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3301 prompter.set_prompt (_("New name of snapshot"));
3302 prompter.set_initial_text (old_name);
3304 if (prompter.run() == RESPONSE_ACCEPT) {
3305 prompter.get_result (new_name);
3306 if (new_name.length()) {
3307 session->rename_state (old_name, new_name);
3308 redisplay_snapshots ();
3315 Editor::remove_snapshot (Glib::ustring name)
3317 vector<string> choices;
3319 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3321 choices.push_back (_("No, do nothing."));
3322 choices.push_back (_("Yes, remove it."));
3324 Gtkmm2ext::Choice prompter (prompt, choices);
3326 if (prompter.run () == 1) {
3327 session->remove_state (name);
3328 redisplay_snapshots ();
3333 Editor::redisplay_snapshots ()
3339 vector<string*>* states;
3341 if ((states = session->possible_states()) == 0) {
3345 snapshot_display_model->clear ();
3347 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3348 string statename = *(*i);
3349 TreeModel::Row row = *(snapshot_display_model->append());
3351 /* this lingers on in case we ever want to change the visible
3352 name of the snapshot.
3355 string display_name;
3356 display_name = statename;
3358 if (statename == session->snap_name()) {
3359 snapshot_display.get_selection()->select(row);
3362 row[snapshot_display_columns.visible_name] = display_name;
3363 row[snapshot_display_columns.real_name] = statename;
3370 Editor::session_state_saved (string snap_name)
3372 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3373 redisplay_snapshots ();
3377 Editor::maximise_editing_space ()
3379 initial_ruler_update_required = true;
3381 mouse_mode_tearoff->set_visible (false);
3382 tools_tearoff->set_visible (false);
3384 pre_maximal_pane_position = edit_pane.get_position();
3385 pre_maximal_editor_width = this->get_width();
3387 if(post_maximal_pane_position == 0) {
3388 post_maximal_pane_position = edit_pane.get_width();
3393 if(post_maximal_editor_width) {
3394 edit_pane.set_position (post_maximal_pane_position -
3395 abs(post_maximal_editor_width - pre_maximal_editor_width));
3397 edit_pane.set_position (post_maximal_pane_position);
3402 Editor::restore_editing_space ()
3404 initial_ruler_update_required = true;
3406 // user changed width of pane during fullscreen
3407 if(post_maximal_pane_position != edit_pane.get_position()) {
3408 post_maximal_pane_position = edit_pane.get_position();
3413 mouse_mode_tearoff->set_visible (true);
3414 tools_tearoff->set_visible (true);
3415 post_maximal_editor_width = this->get_width();
3418 edit_pane.set_position (
3419 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3424 Editor::new_playlists ()
3426 begin_reversible_command (_("new playlists"));
3427 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3428 commit_reversible_command ();
3432 Editor::copy_playlists ()
3434 begin_reversible_command (_("copy playlists"));
3435 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3436 commit_reversible_command ();
3440 Editor::clear_playlists ()
3442 begin_reversible_command (_("clear playlists"));
3443 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3444 commit_reversible_command ();
3448 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3450 atv.use_new_playlist (sz > 1 ? false : true);
3454 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3456 atv.use_copy_playlist (sz > 1 ? false : true);
3460 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3462 atv.clear_playlist ();
3466 Editor::on_key_press_event (GdkEventKey* ev)
3468 return key_press_focus_accelerator_handler (*this, ev);
3472 Editor::reset_x_origin (nframes_t frame)
3474 queue_visual_change (frame);
3478 Editor::reset_zoom (double fpu)
3480 queue_visual_change (fpu);
3484 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3486 reset_x_origin (frame);
3491 Editor::set_frames_per_unit (double fpu)
3495 /* this is the core function that controls the zoom level of the canvas. it is called
3496 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3499 if (fpu == frames_per_unit) {
3507 // convert fpu to frame count
3509 frames = (nframes_t) floor (fpu * canvas_width);
3511 /* don't allow zooms that fit more than the maximum number
3512 of frames into an 800 pixel wide space.
3515 if (max_frames / fpu < 800.0) {
3519 if (fpu == frames_per_unit) {
3523 frames_per_unit = fpu;
3525 if (frames != zoom_range_clock.current_duration()) {
3526 zoom_range_clock.set (frames);
3529 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3530 if (!selection->tracks.empty()) {
3531 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3532 (*i)->reshow_selection (selection->time);
3535 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3536 (*i)->reshow_selection (selection->time);
3541 ZoomChanged (); /* EMIT_SIGNAL */
3543 reset_hscrollbar_stepping ();
3544 reset_scrolling_region ();
3546 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3547 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3553 Editor::queue_visual_change (nframes_t where)
3555 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3556 pending_visual_change.time_origin = where;
3558 if (pending_visual_change.idle_handler_id < 0) {
3559 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3564 Editor::queue_visual_change (double fpu)
3566 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3567 pending_visual_change.frames_per_unit = fpu;
3569 if (pending_visual_change.idle_handler_id < 0) {
3570 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3575 Editor::_idle_visual_changer (void* arg)
3577 return static_cast<Editor*>(arg)->idle_visual_changer ();
3581 Editor::idle_visual_changer ()
3583 VisualChange::Type p = pending_visual_change.pending;
3585 pending_visual_change.pending = (VisualChange::Type) 0;
3586 pending_visual_change.idle_handler_id = -1;
3588 if (p & VisualChange::ZoomLevel) {
3589 set_frames_per_unit (pending_visual_change.frames_per_unit);
3592 if (p & VisualChange::TimeOrigin) {
3593 if (pending_visual_change.time_origin != leftmost_frame) {
3594 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3595 /* the signal handler will do the rest */
3597 update_fixed_rulers();
3598 redisplay_tempo (true);
3602 return 0; /* this is always a one-shot call */
3605 struct EditorOrderTimeAxisSorter {
3606 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3607 return a->order < b->order;
3612 Editor::sort_track_selection ()
3614 EditorOrderTimeAxisSorter cmp;
3615 selection->tracks.sort (cmp);
3619 Editor::edit_cursor_position(bool sync)
3621 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3622 edit_cursor_clock.set(edit_cursor->current_frame, true);
3625 return edit_cursor->current_frame;