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 = Config->canvasvar_LocationMarker.get();
316 location_range_color = Config->canvasvar_LocationRange.get();
317 location_cd_marker_color = Config->canvasvar_LocationCDMarker.get();
318 location_loop_color = Config->canvasvar_LocationLoop.get();
319 location_punch_color = Config->canvasvar_LocationPunch.get();
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, 4, 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 /* re-hide editor list if necessary */
817 editor_list_button_toggled ();
819 /* now reset all audio_time_axis heights, because widgets might need
825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
826 tv = (static_cast<TimeAxisView*>(*i));
832 Editor::tie_vertical_scrolling ()
834 double y1 = vertical_adjustment.get_value();
835 controls_layout.get_vadjustment()->set_value (y1);
836 playhead_cursor->set_y_axis(y1);
837 edit_cursor->set_y_axis(y1);
841 Editor::instant_save ()
843 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
848 session->add_instant_xml(get_state());
850 Config->add_instant_xml(get_state());
855 Editor::edit_cursor_clock_changed()
857 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
858 edit_cursor->set_position (edit_cursor_clock.current_time());
864 Editor::zoom_adjustment_changed ()
870 double fpu = zoom_range_clock.current_duration() / canvas_width;
874 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
875 } else if (fpu > session->current_end_frame() / canvas_width) {
876 fpu = session->current_end_frame() / canvas_width;
877 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
884 Editor::control_scroll (float fraction)
886 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
892 double step = fraction * current_page_frames();
895 if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
897 } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
898 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
900 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
903 /* move visuals, we'll catch up with it later */
905 playhead_cursor->set_position (target);
907 if (target > (current_page_frames() / 2)) {
908 /* try to center PH in window */
909 reset_x_origin (target - (current_page_frames()/2));
914 /* cancel the existing */
916 control_scroll_connection.disconnect ();
918 /* add the next one */
920 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
924 Editor::deferred_control_scroll (nframes_t target)
926 session->request_locate (target);
931 Editor::on_realize ()
933 Window::on_realize ();
938 Editor::start_scrolling ()
940 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
941 (mem_fun(*this, &Editor::update_current_screen));
945 Editor::stop_scrolling ()
947 scroll_connection.disconnect ();
951 Editor::map_position_change (nframes_t frame)
953 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
955 if (session == 0 || !_follow_playhead) {
959 center_screen (frame);
960 playhead_cursor->set_position (frame);
964 Editor::center_screen (nframes_t frame)
966 double page = canvas_width * frames_per_unit;
968 /* if we're off the page, then scroll.
971 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
972 center_screen_internal (frame, page);
977 Editor::center_screen_internal (nframes_t frame, float page)
982 frame -= (nframes_t) page;
987 reset_x_origin (frame);
991 Editor::handle_new_duration ()
993 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
995 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
997 if (new_end > last_canvas_frame) {
998 last_canvas_frame = new_end;
999 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1000 reset_scrolling_region ();
1003 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1007 Editor::update_title_s (const string & snap_name)
1009 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1015 Editor::update_title ()
1017 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1020 bool dirty = session->dirty();
1022 string session_name;
1024 if (session->snap_name() != session->name()) {
1025 session_name = session->snap_name();
1027 session_name = session->name();
1031 session_name = "*" + session_name;
1034 WindowTitle title(session_name);
1035 title += Glib::get_application_name();
1036 set_title (title.get_string());
1041 Editor::connect_to_session (Session *t)
1045 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1048 /* catch up with the playhead */
1050 session->request_locate (playhead_cursor->current_frame);
1052 if (first_action_message) {
1053 first_action_message->hide();
1058 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1059 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1061 /* These signals can all be emitted by a non-GUI thread. Therefore the
1062 handlers for them must not attempt to directly interact with the GUI,
1063 but use Gtkmm2ext::UI::instance()->call_slot();
1066 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1067 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1068 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1069 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1070 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1071 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1072 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1073 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1074 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1075 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1076 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1077 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1078 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1079 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1081 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1083 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1085 edit_groups_changed ();
1087 edit_cursor_clock.set_session (session);
1088 zoom_range_clock.set_session (session);
1089 _playlist_selector->set_session (session);
1090 nudge_clock.set_session (session);
1093 if (analysis_window != 0)
1094 analysis_window->set_session (session);
1097 Location* loc = session->locations()->auto_loop_location();
1099 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1100 if (loc->start() == loc->end()) {
1101 loc->set_end (loc->start() + 1);
1103 session->locations()->add (loc, false);
1104 session->set_auto_loop_location (loc);
1107 loc->set_name (_("Loop"));
1110 loc = session->locations()->auto_punch_location();
1112 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1113 if (loc->start() == loc->end()) {
1114 loc->set_end (loc->start() + 1);
1116 session->locations()->add (loc, false);
1117 session->set_auto_punch_location (loc);
1120 loc->set_name (_("Punch"));
1123 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1125 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1127 refresh_location_display ();
1128 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1129 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1130 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1131 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1132 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1134 handle_new_duration ();
1136 redisplay_regions ();
1137 redisplay_named_selections ();
1138 redisplay_snapshots ();
1140 initial_route_list_display ();
1142 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1143 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1146 restore_ruler_visibility ();
1147 //tempo_map_changed (Change (0));
1148 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1152 /* don't show master bus in a new session */
1154 if (ARDOUR_UI::instance()->session_is_new ()) {
1156 TreeModel::Children rows = route_display_model->children();
1157 TreeModel::Children::iterator i;
1159 no_route_list_redisplay = true;
1161 for (i = rows.begin(); i != rows.end(); ++i) {
1162 TimeAxisView *tv = (*i)[route_display_columns.tv];
1163 RouteTimeAxisView *rtv;
1165 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1166 if (rtv->route()->master()) {
1167 route_list_display.get_selection()->unselect (i);
1172 no_route_list_redisplay = false;
1173 redisplay_route_list ();
1176 /* register for undo history */
1178 session->register_with_memento_command_factory(_id, this);
1182 Editor::build_cursors ()
1184 using namespace Gdk;
1186 Gdk::Color mbg ("#000000" ); /* Black */
1187 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1190 RefPtr<Bitmap> source, mask;
1191 source = Bitmap::create (mag_bits, mag_width, mag_height);
1192 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1193 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1196 Gdk::Color fbg ("#ffffff" );
1197 Gdk::Color ffg ("#000000" );
1200 RefPtr<Bitmap> source, mask;
1202 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1203 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1204 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1208 RefPtr<Bitmap> source, mask;
1209 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1210 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1211 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1214 grabber_cursor = new Gdk::Cursor (HAND2);
1215 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1216 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1217 selector_cursor = new Gdk::Cursor (XTERM);
1218 time_fx_cursor = new Gdk::Cursor (SIZING);
1219 wait_cursor = new Gdk::Cursor (WATCH);
1220 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1223 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1225 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1227 using namespace Menu_Helpers;
1228 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1231 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1235 MenuList& items (fade_context_menu.items());
1239 switch (item_type) {
1241 case FadeInHandleItem:
1242 if (arv->audio_region()->fade_in_active()) {
1243 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1245 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1248 items.push_back (SeparatorElem());
1250 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1251 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1252 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1253 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1254 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1258 case FadeOutHandleItem:
1259 if (arv->audio_region()->fade_out_active()) {
1260 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1262 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1265 items.push_back (SeparatorElem());
1267 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1268 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1269 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1270 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1271 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1276 fatal << _("programming error: ")
1277 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1282 fade_context_menu.popup (button, time);
1285 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1287 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1289 build_track_context_menu (frame)->popup (button, time);
1293 Editor::build_track_context_menu (nframes_t frame)
1295 using namespace Menu_Helpers;
1297 Menu* menu = manage (new Menu);
1298 MenuList& edit_items = menu->items();
1301 /* Build the general `track' context menu, adding what is appropriate given
1302 the current selection */
1304 /* XXX: currently crossfades can't be selected, so we can't use the selection
1305 to decide which crossfades to mention in the menu. I believe this will
1306 change at some point. For now we have to use clicked_trackview to decide. */
1307 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1310 boost::shared_ptr<Diskstream> ds;
1311 boost::shared_ptr<Playlist> pl;
1312 boost::shared_ptr<AudioPlaylist> apl;
1314 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1316 AudioPlaylist::Crossfades xfades;
1317 apl->crossfades_at (frame, xfades);
1319 bool many = xfades.size() > 1;
1321 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1322 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1327 if (!selection->time.empty()) {
1328 add_selection_context_items (edit_items);
1331 if (!selection->regions.empty()) {
1332 add_region_context_items (edit_items);
1335 if (!selection->tracks.empty()) {
1336 add_bus_or_audio_track_context_items (edit_items);
1339 menu->set_name ("ArdourContextMenu");
1346 Editor::analyze_region_selection()
1348 if (analysis_window == 0) {
1349 analysis_window = new AnalysisWindow();
1352 analysis_window->set_session(session);
1354 analysis_window->show_all();
1357 analysis_window->set_regionmode();
1358 analysis_window->analyze();
1360 analysis_window->present();
1364 Editor::analyze_range_selection()
1366 if (analysis_window == 0) {
1367 analysis_window = new AnalysisWindow();
1370 analysis_window->set_session(session);
1372 analysis_window->show_all();
1375 analysis_window->set_rangemode();
1376 analysis_window->analyze();
1378 analysis_window->present();
1380 #endif /* FFT_ANALYSIS */
1383 /** Add context menu items relevant to crossfades.
1384 * @param edit_items List to add the items to.
1387 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1389 using namespace Menu_Helpers;
1390 Menu *xfade_menu = manage (new Menu);
1391 MenuList& items = xfade_menu->items();
1392 xfade_menu->set_name ("ArdourContextMenu");
1395 if (xfade->active()) {
1401 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1402 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1404 if (xfade->can_follow_overlap()) {
1406 if (xfade->following_overlap()) {
1407 str = _("Convert to short");
1409 str = _("Convert to full");
1412 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1416 str = xfade->out()->name();
1418 str += xfade->in()->name();
1420 str = _("Crossfade");
1423 edit_items.push_back (MenuElem (str, *xfade_menu));
1424 edit_items.push_back (SeparatorElem());
1428 Editor::xfade_edit_left_region ()
1430 if (clicked_crossfadeview) {
1431 clicked_crossfadeview->left_view.show_region_editor ();
1436 Editor::xfade_edit_right_region ()
1438 if (clicked_crossfadeview) {
1439 clicked_crossfadeview->right_view.show_region_editor ();
1443 /** Add an element to a menu, settings its sensitivity.
1444 * @param m Menu to add to.
1445 * @param e Element to add.
1446 * @param s true to make sensitive, false to make insensitive
1449 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1453 m.back().set_sensitive (false);
1457 /** Add context menu items relevant to regions.
1458 * @param edit_items List to add the items to.
1461 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1463 using namespace Menu_Helpers;
1464 Menu *region_menu = manage (new Menu);
1465 MenuList& items = region_menu->items();
1466 region_menu->set_name ("ArdourContextMenu");
1468 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1469 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1470 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1472 Menu* sync_point_menu = manage (new Menu);
1473 MenuList& sync_point_items = sync_point_menu->items();
1474 sync_point_menu->set_name("ArdourContextMenu");
1476 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1477 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1479 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1481 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1483 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1485 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1488 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1491 items.push_back (SeparatorElem());
1493 items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1494 items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1495 items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1496 items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1497 items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1498 items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1499 items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1500 items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1502 /* We allow "Original position" if at least one region is not at its
1505 RegionSelection::iterator i = selection->regions.begin();
1506 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1510 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1512 items.push_back (SeparatorElem());
1514 /* Find out if we have a selected audio region */
1515 i = selection->regions.begin();
1516 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1519 bool const have_selected_audio_region = (i != selection->regions.end());
1521 if (have_selected_audio_region) {
1523 Menu* envelopes_menu = manage (new Menu);
1524 MenuList& envelopes_items = envelopes_menu->items();
1525 envelopes_menu->set_name ("ArdourContextMenu");
1527 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1528 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1529 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1530 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1531 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1533 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1535 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1536 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1539 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
1540 items.push_back (SeparatorElem());
1543 /* range related stuff */
1545 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1547 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1549 items.push_back (SeparatorElem());
1553 Menu *nudge_menu = manage (new Menu());
1554 MenuList& nudge_items = nudge_menu->items();
1555 nudge_menu->set_name ("ArdourContextMenu");
1557 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1558 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1559 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1560 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1562 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1564 Menu *trim_menu = manage (new Menu);
1565 MenuList& trim_items = trim_menu->items();
1566 trim_menu->set_name ("ArdourContextMenu");
1568 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1569 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1571 items.push_back (MenuElem (_("Trim"), *trim_menu));
1572 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1573 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1574 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1575 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1576 items.push_back (SeparatorElem());
1577 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1579 /* OK, stick the region submenu at the top of the list, and then add
1583 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1584 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1587 /** Add context menu items relevant to selection ranges.
1588 * @param edit_items List to add the items to.
1591 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1593 using namespace Menu_Helpers;
1594 Menu *selection_menu = manage (new Menu);
1595 MenuList& items = selection_menu->items();
1596 selection_menu->set_name ("ArdourContextMenu");
1598 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1599 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1602 items.push_back (SeparatorElem());
1603 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1606 items.push_back (SeparatorElem());
1607 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1608 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1610 items.push_back (SeparatorElem());
1611 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1612 items.push_back (SeparatorElem());
1613 items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1614 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1615 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1616 items.push_back (SeparatorElem());
1617 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1618 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1619 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1620 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1621 items.push_back (SeparatorElem());
1622 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1623 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1625 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1626 edit_items.push_back (SeparatorElem());
1629 /** Add context menu items relevant to busses or audio tracks.
1630 * @param edit_items List to add the items to.
1633 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1635 using namespace Menu_Helpers;
1637 /* We add every possible action here, and de-sensitize things
1638 that aren't allowed. The sensitivity logic is a bit spread out;
1639 on the one hand I'm using things like can_cut_copy (), which is
1640 reasonably complicated and so perhaps better near the function that
1641 it expresses sensitivity for, and on the other hand checks
1642 in this function as well. You can't really have can_* for everything
1643 or the number of methods would get silly. */
1645 bool const one_selected_region = selection->regions.size() == 1;
1647 /* Count the number of selected audio tracks */
1648 int n_audio_tracks = 0;
1649 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1650 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1651 if (r && r->is_audio_track()) {
1658 Menu *play_menu = manage (new Menu);
1659 MenuList& play_items = play_menu->items();
1660 play_menu->set_name ("ArdourContextMenu");
1662 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1663 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1664 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1666 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1668 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1672 Menu *select_menu = manage (new Menu);
1673 MenuList& select_items = select_menu->items();
1674 select_menu->set_name ("ArdourContextMenu");
1676 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1678 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1680 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1682 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1684 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1686 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1687 select_items.push_back (SeparatorElem());
1689 if (n_audio_tracks) {
1690 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1691 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1694 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1695 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1696 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1697 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1699 if (n_audio_tracks) {
1700 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1703 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1707 Menu *cutnpaste_menu = manage (new Menu);
1708 MenuList& cutnpaste_items = cutnpaste_menu->items();
1709 cutnpaste_menu->set_name ("ArdourContextMenu");
1711 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1713 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1715 if (n_audio_tracks) {
1716 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1717 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1719 cutnpaste_items.push_back (SeparatorElem());
1721 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1722 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1723 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1725 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1728 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1730 if (n_audio_tracks) {
1732 Menu *track_menu = manage (new Menu);
1733 MenuList& track_items = track_menu->items();
1734 track_menu->set_name ("ArdourContextMenu");
1736 /* Adding new material */
1738 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);
1740 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1744 Menu *nudge_menu = manage (new Menu());
1745 MenuList& nudge_items = nudge_menu->items();
1746 nudge_menu->set_name ("ArdourContextMenu");
1748 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1749 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1751 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1753 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1755 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1757 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1759 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1761 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1763 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1766 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1767 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1769 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1770 edit_items.push_back (MenuElem (str, *track_menu));
1774 /* CURSOR SETTING AND MARKS AND STUFF */
1777 Editor::set_snap_to (SnapType st)
1780 string str = snap_type_strings[(int) st];
1782 if (str != snap_type_selector.get_active_text()) {
1783 snap_type_selector.set_active_text (str);
1788 switch (snap_type) {
1789 case SnapToAThirtysecondBeat:
1790 case SnapToASixteenthBeat:
1791 case SnapToAEighthBeat:
1792 case SnapToAQuarterBeat:
1793 case SnapToAThirdBeat:
1794 update_tempo_based_rulers ();
1802 Editor::set_snap_mode (SnapMode mode)
1805 string str = snap_mode_strings[(int)mode];
1807 if (str != snap_mode_selector.get_active_text ()) {
1808 snap_mode_selector.set_active_text (str);
1815 Editor::set_state (const XMLNode& node)
1817 const XMLProperty* prop;
1819 int x, y, xoff, yoff;
1822 if ((prop = node.property ("id")) != 0) {
1823 _id = prop->value ();
1826 if ((geometry = find_named_node (node, "geometry")) == 0) {
1828 g.base_width = default_width;
1829 g.base_height = default_height;
1837 g.base_width = atoi(geometry->property("x_size")->value());
1838 g.base_height = atoi(geometry->property("y_size")->value());
1839 x = atoi(geometry->property("x_pos")->value());
1840 y = atoi(geometry->property("y_pos")->value());
1841 xoff = atoi(geometry->property("x_off")->value());
1842 yoff = atoi(geometry->property("y_off")->value());
1845 set_default_size (g.base_width, g.base_height);
1848 if (session && (prop = node.property ("playhead"))) {
1849 nframes_t pos = atol (prop->value().c_str());
1850 playhead_cursor->set_position (pos);
1852 playhead_cursor->set_position (0);
1854 /* reset_x_origin() doesn't work right here, since the old
1855 position may be zero already, and it does nothing in such
1860 horizontal_adjustment.set_value (0);
1863 if (session && (prop = node.property ("edit-cursor"))) {
1864 nframes_t pos = atol (prop->value().c_str());
1865 edit_cursor->set_position (pos);
1867 edit_cursor->set_position (0);
1870 if ((prop = node.property ("mixer-width"))) {
1871 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1874 if ((prop = node.property ("zoom-focus"))) {
1875 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1878 if ((prop = node.property ("zoom"))) {
1879 reset_zoom (PBD::atof (prop->value()));
1882 if ((prop = node.property ("snap-to"))) {
1883 set_snap_to ((SnapType) atoi (prop->value()));
1886 if ((prop = node.property ("snap-mode"))) {
1887 set_snap_mode ((SnapMode) atoi (prop->value()));
1890 if ((prop = node.property ("mouse-mode"))) {
1891 MouseMode m = str2mousemode(prop->value());
1892 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1893 set_mouse_mode (m, true);
1895 mouse_mode = MouseGain; /* lie, to force the mode switch */
1896 set_mouse_mode (MouseObject, true);
1899 if ((prop = node.property ("show-waveforms"))) {
1900 bool yn = (prop->value() == "yes");
1901 _show_waveforms = !yn;
1902 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1904 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1905 /* do it twice to force the change */
1906 tact->set_active (!yn);
1907 tact->set_active (yn);
1911 if ((prop = node.property ("show-waveforms-recording"))) {
1912 bool yn = (prop->value() == "yes");
1913 _show_waveforms_recording = !yn;
1914 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1916 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1917 /* do it twice to force the change */
1918 tact->set_active (!yn);
1919 tact->set_active (yn);
1923 if ((prop = node.property ("show-measures"))) {
1924 bool yn = (prop->value() == "yes");
1925 _show_measures = !yn;
1926 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1928 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1929 /* do it twice to force the change */
1930 tact->set_active (!yn);
1931 tact->set_active (yn);
1935 if ((prop = node.property ("follow-playhead"))) {
1936 bool yn = (prop->value() == "yes");
1937 set_follow_playhead (yn);
1938 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1940 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1941 if (tact->get_active() != yn) {
1942 tact->set_active (yn);
1947 if ((prop = node.property ("region-list-sort-type"))) {
1948 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
1949 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1952 if ((prop = node.property ("xfades-visible"))) {
1953 bool yn = (prop->value() == "yes");
1954 _xfade_visibility = !yn;
1955 // set_xfade_visibility (yn);
1958 if ((prop = node.property ("show-editor-mixer"))) {
1960 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1963 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1964 bool yn = (prop->value() == X_("yes"));
1966 /* do it twice to force the change */
1968 tact->set_active (!yn);
1969 tact->set_active (yn);
1973 if ((prop = node.property ("show-editor-list"))) {
1975 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
1979 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1980 bool yn = (prop->value() == X_("yes"));
1982 /* do it twice to force the change */
1984 tact->set_active (!yn);
1985 tact->set_active (yn);
1994 Editor::get_state ()
1996 XMLNode* node = new XMLNode ("Editor");
1999 _id.print (buf, sizeof (buf));
2000 node->add_property ("id", buf);
2002 if (is_realized()) {
2003 Glib::RefPtr<Gdk::Window> win = get_window();
2005 int x, y, xoff, yoff, width, height;
2006 win->get_root_origin(x, y);
2007 win->get_position(xoff, yoff);
2008 win->get_size(width, height);
2010 XMLNode* geometry = new XMLNode ("geometry");
2012 snprintf(buf, sizeof(buf), "%d", width);
2013 geometry->add_property("x_size", string(buf));
2014 snprintf(buf, sizeof(buf), "%d", height);
2015 geometry->add_property("y_size", string(buf));
2016 snprintf(buf, sizeof(buf), "%d", x);
2017 geometry->add_property("x_pos", string(buf));
2018 snprintf(buf, sizeof(buf), "%d", y);
2019 geometry->add_property("y_pos", string(buf));
2020 snprintf(buf, sizeof(buf), "%d", xoff);
2021 geometry->add_property("x_off", string(buf));
2022 snprintf(buf, sizeof(buf), "%d", yoff);
2023 geometry->add_property("y_off", string(buf));
2024 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2025 geometry->add_property("edit_pane_pos", string(buf));
2027 node->add_child_nocopy (*geometry);
2030 maybe_add_mixer_strip_width (*node);
2032 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2033 node->add_property ("zoom-focus", buf);
2034 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2035 node->add_property ("zoom", buf);
2036 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2037 node->add_property ("snap-to", buf);
2038 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2039 node->add_property ("snap-mode", buf);
2041 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2042 node->add_property ("playhead", buf);
2043 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2044 node->add_property ("edit-cursor", buf);
2046 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2047 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2048 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2049 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2050 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2051 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2052 node->add_property ("mouse-mode", enum2str(mouse_mode));
2054 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2056 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2057 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2060 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2062 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2063 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2072 Editor::trackview_by_y_position (double y)
2074 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2078 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2087 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2089 Location* before = 0;
2090 Location* after = 0;
2096 const nframes64_t one_second = session->frame_rate();
2097 const nframes64_t one_minute = session->frame_rate() * 60;
2098 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2099 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2100 nframes64_t presnap = start;
2102 switch (snap_type) {
2108 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2110 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2114 case SnapToSMPTEFrame:
2115 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2116 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2118 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2122 case SnapToSMPTESeconds:
2123 if (session->smpte_offset_negative())
2125 start += session->smpte_offset ();
2127 start -= session->smpte_offset ();
2129 if (start % one_smpte_second > one_smpte_second / 2) {
2130 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2132 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2135 if (session->smpte_offset_negative())
2137 start -= session->smpte_offset ();
2139 start += session->smpte_offset ();
2143 case SnapToSMPTEMinutes:
2144 if (session->smpte_offset_negative())
2146 start += session->smpte_offset ();
2148 start -= session->smpte_offset ();
2150 if (start % one_smpte_minute > one_smpte_minute / 2) {
2151 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2153 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2155 if (session->smpte_offset_negative())
2157 start -= session->smpte_offset ();
2159 start += session->smpte_offset ();
2164 if (start % one_second > one_second / 2) {
2165 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2167 start = (nframes_t) floor ((double) start / one_second) * one_second;
2172 if (start % one_minute > one_minute / 2) {
2173 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2175 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2180 start = session->tempo_map().round_to_bar (start, direction);
2184 start = session->tempo_map().round_to_beat (start, direction);
2187 case SnapToAThirtysecondBeat:
2188 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2191 case SnapToASixteenthBeat:
2192 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2195 case SnapToAEighthBeat:
2196 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2199 case SnapToAQuarterBeat:
2200 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2203 case SnapToAThirdBeat:
2204 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2207 case SnapToEditCursor:
2208 start = edit_cursor->current_frame;
2216 before = session->locations()->first_location_before (start);
2217 after = session->locations()->first_location_after (start);
2219 if (direction < 0) {
2221 start = before->start();
2225 } else if (direction > 0) {
2227 start = after->start();
2229 start = session->current_end_frame();
2234 /* find nearest of the two */
2235 if ((start - before->start()) < (after->start() - start)) {
2236 start = before->start();
2238 start = after->start();
2241 start = before->start();
2244 start = after->start();
2251 case SnapToRegionStart:
2252 case SnapToRegionEnd:
2253 case SnapToRegionSync:
2254 case SnapToRegionBoundary:
2255 if (!region_boundary_cache.empty()) {
2256 vector<nframes_t>::iterator i;
2258 if (direction > 0) {
2259 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2261 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2264 if (i != region_boundary_cache.end()) {
2267 start = region_boundary_cache.back();
2273 switch (snap_mode) {
2279 if (presnap > start) {
2280 if (presnap > (start + unit_to_frame(snap_threshold))) {
2284 } else if (presnap < start) {
2285 if (presnap < (start - unit_to_frame(snap_threshold))) {
2297 Editor::setup_toolbar ()
2301 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2304 /* Mode Buttons (tool selection) */
2306 vector<ToggleButton *> mouse_mode_buttons;
2308 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2309 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2310 mouse_mode_buttons.push_back (&mouse_move_button);
2311 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2312 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2313 mouse_mode_buttons.push_back (&mouse_select_button);
2314 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2315 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2316 mouse_mode_buttons.push_back (&mouse_gain_button);
2317 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2318 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2319 mouse_mode_buttons.push_back (&mouse_zoom_button);
2320 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2321 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2322 mouse_mode_buttons.push_back (&mouse_timefx_button);
2323 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2324 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2325 mouse_mode_buttons.push_back (&mouse_audition_button);
2327 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2329 HBox* mode_box = manage(new HBox);
2330 mode_box->set_border_width (2);
2331 mode_box->set_spacing(4);
2332 mouse_mode_button_box.set_spacing(1);
2333 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2334 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2335 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2336 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2337 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2338 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2339 mouse_mode_button_box.set_homogeneous(true);
2341 vector<string> edit_mode_strings;
2342 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2343 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2345 edit_mode_selector.set_name ("EditModeSelector");
2346 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2347 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2348 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2350 mode_box->pack_start(edit_mode_selector);
2351 mode_box->pack_start(mouse_mode_button_box);
2353 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2354 mouse_mode_tearoff->set_name ("MouseModeBase");
2356 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2357 &mouse_mode_tearoff->tearoff_window()));
2358 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2359 &mouse_mode_tearoff->tearoff_window(), 1));
2360 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2361 &mouse_mode_tearoff->tearoff_window()));
2362 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2363 &mouse_mode_tearoff->tearoff_window(), 1));
2365 mouse_move_button.set_name ("MouseModeButton");
2366 mouse_select_button.set_name ("MouseModeButton");
2367 mouse_gain_button.set_name ("MouseModeButton");
2368 mouse_zoom_button.set_name ("MouseModeButton");
2369 mouse_timefx_button.set_name ("MouseModeButton");
2370 mouse_audition_button.set_name ("MouseModeButton");
2372 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2373 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2374 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2375 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2376 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2377 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2379 mouse_move_button.unset_flags (CAN_FOCUS);
2380 mouse_select_button.unset_flags (CAN_FOCUS);
2381 mouse_gain_button.unset_flags (CAN_FOCUS);
2382 mouse_zoom_button.unset_flags (CAN_FOCUS);
2383 mouse_timefx_button.unset_flags (CAN_FOCUS);
2384 mouse_audition_button.unset_flags (CAN_FOCUS);
2386 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2387 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2389 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2390 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2391 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2392 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2393 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2395 // mouse_move_button.set_active (true);
2400 zoom_box.set_spacing (1);
2401 zoom_box.set_border_width (2);
2403 zoom_in_button.set_name ("EditorTimeButton");
2404 zoom_in_button.set_size_request(-1,16);
2405 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2406 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2407 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2409 zoom_out_button.set_name ("EditorTimeButton");
2410 zoom_out_button.set_size_request(-1,16);
2411 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2412 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2413 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2415 zoom_out_full_button.set_name ("EditorTimeButton");
2416 zoom_out_full_button.set_size_request(-1,16);
2417 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2418 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2419 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2421 zoom_focus_selector.set_name ("ZoomFocusSelector");
2422 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2423 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2424 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2425 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2427 zoom_box.pack_start (zoom_focus_selector, true, true);
2428 zoom_box.pack_start (zoom_out_button, false, false);
2429 zoom_box.pack_start (zoom_in_button, false, false);
2430 zoom_box.pack_start (zoom_out_full_button, false, false);
2432 /* Edit Cursor / Snap */
2434 snap_box.set_spacing (1);
2435 snap_box.set_border_width (2);
2437 snap_type_selector.set_name ("SnapTypeSelector");
2438 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2439 set_popdown_strings (snap_type_selector, snap_type_strings);
2440 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2441 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2443 snap_mode_selector.set_name ("SnapModeSelector");
2444 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2445 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2446 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2448 snap_box.pack_start (edit_cursor_clock, false, false);
2449 snap_box.pack_start (snap_mode_selector, false, false);
2450 snap_box.pack_start (snap_type_selector, false, false);
2455 HBox *nudge_box = manage (new HBox);
2456 nudge_box->set_spacing(1);
2457 nudge_box->set_border_width (2);
2459 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2460 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2462 nudge_box->pack_start (nudge_backward_button, false, false);
2463 nudge_box->pack_start (nudge_forward_button, false, false);
2464 nudge_box->pack_start (nudge_clock, false, false);
2467 /* Pack everything in... */
2469 HBox* hbox = new HBox;
2470 hbox->set_spacing(10);
2472 tools_tearoff = new TearOff (*hbox);
2473 tools_tearoff->set_name ("MouseModeBase");
2475 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2476 &tools_tearoff->tearoff_window()));
2477 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2478 &tools_tearoff->tearoff_window(), 0));
2479 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2480 &tools_tearoff->tearoff_window()));
2481 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2482 &tools_tearoff->tearoff_window(), 0));
2484 toolbar_hbox.set_spacing (10);
2485 toolbar_hbox.set_border_width (1);
2487 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2488 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2491 hbox->pack_start (snap_box, false, false);
2492 // hbox->pack_start (zoom_box, false, false);
2493 hbox->pack_start (*nudge_box, false, false);
2497 toolbar_base.set_name ("ToolBarBase");
2498 toolbar_base.add (toolbar_hbox);
2500 toolbar_frame.set_shadow_type (SHADOW_OUT);
2501 toolbar_frame.set_name ("BaseFrame");
2502 toolbar_frame.add (toolbar_base);
2506 Editor::convert_drop_to_paths (vector<ustring>& paths,
2507 const RefPtr<Gdk::DragContext>& context,
2510 const SelectionData& data,
2519 vector<ustring> uris = data.get_uris();
2523 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2524 are actually URI lists. So do it by hand.
2527 if (data.get_target() != "text/plain") {
2531 /* Parse the "uri-list" format that Nautilus provides,
2532 where each pathname is delimited by \r\n
2535 const char* p = data.get_text().c_str();
2542 while (g_ascii_isspace (*p))
2546 while (*q && (*q != '\n') && (*q != '\r'))
2552 while (q > p && g_ascii_isspace (*q))
2557 uris.push_back (ustring (p, q - p + 1));
2561 p = strchr (p, '\n');
2571 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2572 if ((*i).substr (0,7) == "file://") {
2574 PBD::url_decode (p);
2575 paths.push_back (p.substr (7));
2583 Editor::new_tempo_section ()
2589 Editor::map_transport_state ()
2591 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2593 if (session->transport_stopped()) {
2594 have_pending_keyboard_selection = false;
2597 update_loop_range_view (true);
2602 Editor::State::State ()
2604 selection = new Selection;
2607 Editor::State::~State ()
2613 Editor::get_memento () const
2615 State *state = new State;
2617 store_state (*state);
2618 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2622 Editor::store_state (State& state) const
2624 *state.selection = *selection;
2628 Editor::restore_state (State *state)
2630 if (*selection == *state->selection) {
2634 *selection = *state->selection;
2635 time_selection_changed ();
2636 region_selection_changed ();
2638 /* XXX other selection change handlers? */
2642 Editor::begin_reversible_command (string name)
2645 before = &get_state();
2646 session->begin_reversible_command (name);
2651 Editor::commit_reversible_command ()
2654 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2659 Editor::set_edit_group_solo (Route& route, bool yn)
2661 RouteGroup *edit_group;
2663 if ((edit_group = route.edit_group()) != 0) {
2664 edit_group->apply (&Route::set_solo, yn, this);
2666 route.set_solo (yn, this);
2671 Editor::set_edit_group_mute (Route& route, bool yn)
2673 RouteGroup *edit_group = 0;
2675 if ((edit_group == route.edit_group()) != 0) {
2676 edit_group->apply (&Route::set_mute, yn, this);
2678 route.set_mute (yn, this);
2683 Editor::history_changed ()
2687 if (undo_action && session) {
2688 if (session->undo_depth() == 0) {
2691 label = string_compose(_("Undo (%1)"), session->next_undo());
2693 undo_action->property_label() = label;
2696 if (redo_action && session) {
2697 if (session->redo_depth() == 0) {
2700 label = string_compose(_("Redo (%1)"), session->next_redo());
2702 redo_action->property_label() = label;
2707 Editor::duplicate_dialog (bool dup_region)
2709 if (selection->regions.empty() && (selection->time.length() == 0)) {
2713 ArdourDialog win ("duplicate dialog");
2714 Label label (_("Duplicate how many times?"));
2715 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2716 SpinButton spinner (adjustment);
2718 win.get_vbox()->set_spacing (12);
2719 win.get_vbox()->pack_start (label);
2721 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2722 place, visually. so do this by hand.
2725 win.get_vbox()->pack_start (spinner);
2726 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2731 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2732 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2734 win.set_position (WIN_POS_MOUSE);
2736 spinner.grab_focus ();
2738 switch (win.run ()) {
2739 case RESPONSE_ACCEPT:
2745 float times = adjustment.get_value();
2747 if (!selection->regions.empty()) {
2748 duplicate_some_regions (selection->regions, times);
2750 duplicate_selection (times);
2755 Editor::show_verbose_canvas_cursor ()
2757 verbose_canvas_cursor->raise_to_top();
2758 verbose_canvas_cursor->show();
2759 verbose_cursor_visible = true;
2763 Editor::hide_verbose_canvas_cursor ()
2765 verbose_canvas_cursor->hide();
2766 verbose_cursor_visible = false;
2770 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2772 /* XXX get origin of canvas relative to root window,
2773 add x and y and check compared to gdk_screen_{width,height}
2775 verbose_canvas_cursor->property_text() = txt.c_str();
2776 verbose_canvas_cursor->property_x() = x;
2777 verbose_canvas_cursor->property_y() = y;
2781 Editor::set_verbose_canvas_cursor_text (const string & txt)
2783 verbose_canvas_cursor->property_text() = txt.c_str();
2787 Editor::edit_mode_selection_done ()
2793 string choice = edit_mode_selector.get_active_text();
2794 EditMode mode = Slide;
2796 if (choice == _("Splice Edit")) {
2798 } else if (choice == _("Slide Edit")) {
2802 Config->set_edit_mode (mode);
2806 Editor::snap_type_selection_done ()
2808 string choice = snap_type_selector.get_active_text();
2809 SnapType snaptype = SnapToFrame;
2811 if (choice == _("Beats/3")) {
2812 snaptype = SnapToAThirdBeat;
2813 } else if (choice == _("Beats/4")) {
2814 snaptype = SnapToAQuarterBeat;
2815 } else if (choice == _("Beats/8")) {
2816 snaptype = SnapToAEighthBeat;
2817 } else if (choice == _("Beats/16")) {
2818 snaptype = SnapToASixteenthBeat;
2819 } else if (choice == _("Beats/32")) {
2820 snaptype = SnapToAThirtysecondBeat;
2821 } else if (choice == _("Beats")) {
2822 snaptype = SnapToBeat;
2823 } else if (choice == _("Bars")) {
2824 snaptype = SnapToBar;
2825 } else if (choice == _("Marks")) {
2826 snaptype = SnapToMark;
2827 } else if (choice == _("Edit Cursor")) {
2828 snaptype = SnapToEditCursor;
2829 } else if (choice == _("Region starts")) {
2830 snaptype = SnapToRegionStart;
2831 } else if (choice == _("Region ends")) {
2832 snaptype = SnapToRegionEnd;
2833 } else if (choice == _("Region bounds")) {
2834 snaptype = SnapToRegionBoundary;
2835 } else if (choice == _("Region syncs")) {
2836 snaptype = SnapToRegionSync;
2837 } else if (choice == _("CD Frames")) {
2838 snaptype = SnapToCDFrame;
2839 } else if (choice == _("SMPTE Frames")) {
2840 snaptype = SnapToSMPTEFrame;
2841 } else if (choice == _("SMPTE Seconds")) {
2842 snaptype = SnapToSMPTESeconds;
2843 } else if (choice == _("SMPTE Minutes")) {
2844 snaptype = SnapToSMPTEMinutes;
2845 } else if (choice == _("Seconds")) {
2846 snaptype = SnapToSeconds;
2847 } else if (choice == _("Minutes")) {
2848 snaptype = SnapToMinutes;
2849 } else if (choice == _("None")) {
2850 snaptype = SnapToFrame;
2853 RefPtr<RadioAction> ract = snap_type_action (snaptype);
2855 ract->set_active ();
2860 Editor::snap_mode_selection_done ()
2862 string choice = snap_mode_selector.get_active_text();
2863 SnapMode mode = SnapNormal;
2865 if (choice == _("Normal")) {
2867 } else if (choice == _("Magnetic")) {
2868 mode = SnapMagnetic;
2871 RefPtr<RadioAction> ract = snap_mode_action (mode);
2874 ract->set_active (true);
2879 Editor::zoom_focus_selection_done ()
2881 string choice = zoom_focus_selector.get_active_text();
2882 ZoomFocus focus_type = ZoomFocusLeft;
2884 if (choice == _("Left")) {
2885 focus_type = ZoomFocusLeft;
2886 } else if (choice == _("Right")) {
2887 focus_type = ZoomFocusRight;
2888 } else if (choice == _("Center")) {
2889 focus_type = ZoomFocusCenter;
2890 } else if (choice == _("Play")) {
2891 focus_type = ZoomFocusPlayhead;
2892 } else if (choice == _("Edit")) {
2893 focus_type = ZoomFocusEdit;
2896 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
2899 ract->set_active ();
2904 Editor::edit_controls_button_release (GdkEventButton* ev)
2906 if (Keyboard::is_context_menu_event (ev)) {
2907 ARDOUR_UI::instance()->add_route (this);
2913 Editor::mouse_select_button_release (GdkEventButton* ev)
2915 /* this handles just right-clicks */
2917 if (ev->button != 3) {
2924 Editor::TrackViewList *
2925 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
2928 TrackViewList::iterator i;
2930 v = new TrackViewList;
2932 if (track == 0 && group == 0) {
2936 for (i = track_views.begin(); i != track_views.end (); ++i) {
2940 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
2942 /* just the view for this track
2945 v->push_back (track);
2949 /* views for all tracks in the edit group */
2951 for (i = track_views.begin(); i != track_views.end (); ++i) {
2953 if (group == 0 || (*i)->edit_group() == group) {
2963 Editor::set_zoom_focus (ZoomFocus f)
2965 string str = zoom_focus_strings[(int)f];
2967 if (str != zoom_focus_selector.get_active_text()) {
2968 zoom_focus_selector.set_active_text (str);
2971 if (zoom_focus != f) {
2974 ZoomFocusChanged (); /* EMIT_SIGNAL */
2981 Editor::ensure_float (Window& win)
2983 win.set_transient_for (*this);
2987 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
2989 /* recover or initialize pane positions. do this here rather than earlier because
2990 we don't want the positions to change the child allocations, which they seem to do.
2996 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
2998 static int32_t done;
3001 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3002 width = default_width;
3003 height = default_height;
3005 width = atoi(geometry->property("x_size")->value());
3006 height = atoi(geometry->property("y_size")->value());
3009 if (which == static_cast<Paned*> (&edit_pane)) {
3015 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3016 /* initial allocation is 90% to canvas, 10% to notebook */
3017 pos = (int) floor (alloc.get_width() * 0.90f);
3018 snprintf (buf, sizeof(buf), "%d", pos);
3020 pos = atoi (prop->value());
3023 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3024 edit_pane.set_position (pos);
3025 pre_maximal_pane_position = pos;
3031 Editor::detach_tearoff (Box* b, Window* w)
3033 if (tools_tearoff->torn_off() &&
3034 mouse_mode_tearoff->torn_off()) {
3035 top_hbox.remove (toolbar_frame);
3040 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3042 if (toolbar_frame.get_parent() == 0) {
3043 top_hbox.pack_end (toolbar_frame);
3048 Editor::set_show_measures (bool yn)
3050 if (_show_measures != yn) {
3053 if ((_show_measures = yn) == true) {
3061 Editor::toggle_follow_playhead ()
3063 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3065 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3066 set_follow_playhead (tact->get_active());
3071 Editor::set_follow_playhead (bool yn)
3073 if (_follow_playhead != yn) {
3074 if ((_follow_playhead = yn) == true) {
3076 update_current_screen ();
3083 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3085 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3087 xfade->set_active (!xfade->active());
3092 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3094 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3096 xfade->set_follow_overlap (!xfade->following_overlap());
3101 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3103 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3109 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3113 switch (cew.run ()) {
3114 case RESPONSE_ACCEPT:
3121 xfade->StateChanged (Change (~0));
3125 Editor::playlist_selector () const
3127 return *_playlist_selector;
3131 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3135 ret = nudge_clock.current_duration (pos);
3136 next = ret + 1; /* XXXX fix me */
3142 Editor::end_location_changed (Location* location)
3144 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3145 reset_scrolling_region ();
3149 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3151 ArdourDialog dialog ("playlist deletion dialog");
3152 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3153 "If left alone, no audio files used by it will be cleaned.\n"
3154 "If deleted, audio files used by it alone by will cleaned."),
3157 dialog.set_position (WIN_POS_CENTER);
3158 dialog.get_vbox()->pack_start (label);
3162 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3163 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3164 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3166 switch (dialog.run ()) {
3167 case RESPONSE_ACCEPT:
3168 /* delete the playlist */
3172 case RESPONSE_REJECT:
3173 /* keep the playlist */
3185 Editor::audio_region_selection_covers (nframes_t where)
3187 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3188 if ((*a)->region()->covers (where)) {
3197 Editor::prepare_for_cleanup ()
3199 cut_buffer->clear_regions ();
3200 cut_buffer->clear_playlists ();
3202 selection->clear_regions ();
3203 selection->clear_playlists ();
3207 Editor::transport_loop_location()
3210 return session->locations()->auto_loop_location();
3217 Editor::transport_punch_location()
3220 return session->locations()->auto_punch_location();
3227 Editor::control_layout_scroll (GdkEventScroll* ev)
3229 switch (ev->direction) {
3231 scroll_tracks_up_line ();
3235 case GDK_SCROLL_DOWN:
3236 scroll_tracks_down_line ();
3240 /* no left/right handling yet */
3248 /** A new snapshot has been selected.
3251 Editor::snapshot_display_selection_changed ()
3253 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3255 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3257 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3259 if (snap_name.length() == 0) {
3263 if (session->snap_name() == snap_name) {
3267 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3272 Editor::snapshot_display_button_press (GdkEventButton* ev)
3274 if (ev->button == 3) {
3275 /* Right-click on the snapshot list. Work out which snapshot it
3277 Gtk::TreeModel::Path path;
3278 Gtk::TreeViewColumn* col;
3281 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3282 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3284 Gtk::TreeModel::Row row = *iter;
3285 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3294 /** Pop up the snapshot display context menu.
3295 * @param button Button used to open the menu.
3296 * @param time Menu open time.
3297 * @snapshot_name Name of the snapshot that the menu click was over.
3301 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3303 using namespace Menu_Helpers;
3305 MenuList& items (snapshot_context_menu.items());
3308 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3310 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3312 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3314 snapshot_context_menu.popup (button, time);
3318 Editor::rename_snapshot (Glib::ustring old_name)
3320 ArdourPrompter prompter(true);
3324 prompter.set_name ("Prompter");
3325 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3326 prompter.set_prompt (_("New name of snapshot"));
3327 prompter.set_initial_text (old_name);
3329 if (prompter.run() == RESPONSE_ACCEPT) {
3330 prompter.get_result (new_name);
3331 if (new_name.length()) {
3332 session->rename_state (old_name, new_name);
3333 redisplay_snapshots ();
3340 Editor::remove_snapshot (Glib::ustring name)
3342 vector<string> choices;
3344 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3346 choices.push_back (_("No, do nothing."));
3347 choices.push_back (_("Yes, remove it."));
3349 Gtkmm2ext::Choice prompter (prompt, choices);
3351 if (prompter.run () == 1) {
3352 session->remove_state (name);
3353 redisplay_snapshots ();
3358 Editor::redisplay_snapshots ()
3364 vector<string*>* states;
3366 if ((states = session->possible_states()) == 0) {
3370 snapshot_display_model->clear ();
3372 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3373 string statename = *(*i);
3374 TreeModel::Row row = *(snapshot_display_model->append());
3376 /* this lingers on in case we ever want to change the visible
3377 name of the snapshot.
3380 string display_name;
3381 display_name = statename;
3383 if (statename == session->snap_name()) {
3384 snapshot_display.get_selection()->select(row);
3387 row[snapshot_display_columns.visible_name] = display_name;
3388 row[snapshot_display_columns.real_name] = statename;
3395 Editor::session_state_saved (string snap_name)
3397 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3398 redisplay_snapshots ();
3402 Editor::maximise_editing_space ()
3404 initial_ruler_update_required = true;
3406 mouse_mode_tearoff->set_visible (false);
3407 tools_tearoff->set_visible (false);
3409 pre_maximal_pane_position = edit_pane.get_position();
3410 pre_maximal_editor_width = this->get_width();
3412 if(post_maximal_pane_position == 0) {
3413 post_maximal_pane_position = edit_pane.get_width();
3418 if(post_maximal_editor_width) {
3419 edit_pane.set_position (post_maximal_pane_position -
3420 abs(post_maximal_editor_width - pre_maximal_editor_width));
3422 edit_pane.set_position (post_maximal_pane_position);
3427 Editor::restore_editing_space ()
3429 initial_ruler_update_required = true;
3431 // user changed width of pane during fullscreen
3432 if(post_maximal_pane_position != edit_pane.get_position()) {
3433 post_maximal_pane_position = edit_pane.get_position();
3438 mouse_mode_tearoff->set_visible (true);
3439 tools_tearoff->set_visible (true);
3440 post_maximal_editor_width = this->get_width();
3443 edit_pane.set_position (
3444 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3449 Editor::new_playlists ()
3451 begin_reversible_command (_("new playlists"));
3452 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3453 commit_reversible_command ();
3457 Editor::copy_playlists ()
3459 begin_reversible_command (_("copy playlists"));
3460 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3461 commit_reversible_command ();
3465 Editor::clear_playlists ()
3467 begin_reversible_command (_("clear playlists"));
3468 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3469 commit_reversible_command ();
3473 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3475 atv.use_new_playlist (sz > 1 ? false : true);
3479 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3481 atv.use_copy_playlist (sz > 1 ? false : true);
3485 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3487 atv.clear_playlist ();
3491 Editor::on_key_press_event (GdkEventKey* ev)
3493 return key_press_focus_accelerator_handler (*this, ev);
3497 Editor::reset_x_origin (nframes_t frame)
3499 queue_visual_change (frame);
3503 Editor::reset_zoom (double fpu)
3505 queue_visual_change (fpu);
3509 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3511 reset_x_origin (frame);
3516 Editor::set_frames_per_unit (double fpu)
3520 /* this is the core function that controls the zoom level of the canvas. it is called
3521 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3524 if (fpu == frames_per_unit) {
3532 // convert fpu to frame count
3534 frames = (nframes_t) floor (fpu * canvas_width);
3536 /* don't allow zooms that fit more than the maximum number
3537 of frames into an 800 pixel wide space.
3540 if (max_frames / fpu < 800.0) {
3544 if (fpu == frames_per_unit) {
3548 frames_per_unit = fpu;
3550 if (frames != zoom_range_clock.current_duration()) {
3551 zoom_range_clock.set (frames);
3554 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3555 if (!selection->tracks.empty()) {
3556 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3557 (*i)->reshow_selection (selection->time);
3560 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3561 (*i)->reshow_selection (selection->time);
3566 ZoomChanged (); /* EMIT_SIGNAL */
3568 reset_hscrollbar_stepping ();
3569 reset_scrolling_region ();
3571 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3572 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3578 Editor::queue_visual_change (nframes_t where)
3580 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3581 pending_visual_change.time_origin = where;
3583 if (pending_visual_change.idle_handler_id < 0) {
3584 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3589 Editor::queue_visual_change (double fpu)
3591 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3592 pending_visual_change.frames_per_unit = fpu;
3594 if (pending_visual_change.idle_handler_id < 0) {
3595 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3600 Editor::_idle_visual_changer (void* arg)
3602 return static_cast<Editor*>(arg)->idle_visual_changer ();
3606 Editor::idle_visual_changer ()
3608 VisualChange::Type p = pending_visual_change.pending;
3610 pending_visual_change.pending = (VisualChange::Type) 0;
3611 pending_visual_change.idle_handler_id = -1;
3613 if (p & VisualChange::ZoomLevel) {
3614 set_frames_per_unit (pending_visual_change.frames_per_unit);
3617 if (p & VisualChange::TimeOrigin) {
3618 if (pending_visual_change.time_origin != leftmost_frame) {
3619 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3620 /* the signal handler will do the rest */
3622 update_fixed_rulers();
3623 redisplay_tempo (true);
3627 return 0; /* this is always a one-shot call */
3630 struct EditorOrderTimeAxisSorter {
3631 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3632 return a->order < b->order;
3637 Editor::sort_track_selection ()
3639 EditorOrderTimeAxisSorter cmp;
3640 selection->tracks.sort (cmp);
3644 Editor::edit_cursor_position(bool sync)
3646 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3647 edit_cursor_clock.set(edit_cursor->current_frame, true);
3650 return edit_cursor->current_frame;